Documentation
¶
Overview ¶
Package docker is part of the Redoubt control plane. See CLAUDE.md for its role.
Index ¶
- Constants
- Variables
- func Allowed(method, p string) bool
- func AppContainerName(app, release string) string
- func AppNetworkName(app string) string
- func CopyLogs(w io.Writer, r io.Reader) error
- func IsRootUser(u string) bool
- func NormalizePath(p string) (string, bool)
- func ValidateAppName(name string) error
- func VerifyHardened(insp container.InspectResponse) []string
- type Built
- type Call
- type Client
- func (c *Client) Close() error
- func (c *Client) ConnectContainer(ctx context.Context, networkName, containerID string) error
- func (c *Client) Create(ctx context.Context, spec ContainerSpec) (string, []Warning, error)
- func (c *Client) CreateAndStart(ctx context.Context, spec ContainerSpec) (string, []Warning, error)
- func (c *Client) DisconnectContainer(ctx context.Context, networkName, containerID string) error
- func (c *Client) EnsureNetwork(ctx context.Context, name string, internal bool) (string, error)
- func (c *Client) ImageExists(ctx context.Context, ref string) (bool, error)
- func (c *Client) ImageUser(ctx context.Context, ref string) (string, error)
- func (c *Client) Info(ctx context.Context) (system.Info, error)
- func (c *Client) Inspect(ctx context.Context, id string) (container.InspectResponse, error)
- func (c *Client) ListManaged(ctx context.Context, app string) ([]container.Summary, error)
- func (c *Client) LoadImage(ctx context.Context, tar io.Reader) error
- func (c *Client) Logs(ctx context.Context, id string, follow bool, tail string) (io.ReadCloser, error)
- func (c *Client) Ping(ctx context.Context) error
- func (c *Client) PullImage(ctx context.Context, ref string) error
- func (c *Client) Remove(ctx context.Context, id string, force bool) error
- func (c *Client) RemoveImage(ctx context.Context, ref string) error
- func (c *Client) RemoveNetwork(ctx context.Context, name string) error
- func (c *Client) RemoveVolume(ctx context.Context, name string) error
- func (c *Client) SaveImage(ctx context.Context, ref string) (io.ReadCloser, error)
- func (c *Client) Start(ctx context.Context, id string) error
- func (c *Client) Stop(ctx context.Context, id string, timeout time.Duration) error
- func (c *Client) TagImage(ctx context.Context, source, target string) error
- func (c *Client) Wait(ctx context.Context, id string) (int64, error)
- func (c *Client) WaitHealthy(ctx context.Context, id string, timeout time.Duration) error
- type ContainerSpec
- type Mount
- type Option
- type Overrides
- type Recorder
- type Rule
- type Warning
Constants ¶
const ( LabelManaged = "redoubt.managed" LabelApp = "redoubt.app" LabelKind = "redoubt.kind" LabelRelease = "redoubt.release" LabelTest = "redoubt.test" )
Labels applied to every container the platform creates.
const ( KindApp = "app" KindAddon = "addon" KindJob = "job" // one-shot: backups, scans KindBuilder = "builder" )
Kinds of containers the platform creates.
const ( DefaultUser = "10001:10001" // JobUser is the platform uid: one-shot jobs (scans, dumps, restores) run as it so the 0700 // work directories platformd creates under DataDir are writable to them and nobody else. JobUser = "65532:65532" DefaultMemoryBytes = 512 << 20 // 512 MiB DefaultNanoCPUs = 1_000_000_000 DefaultPidsLimit = 256 // mode=1777: without it Docker creates the tmpfs root-owned 0755 and a non-root process // cannot even create a temp file — which would silently force apps back toward root. DefaultTmpfsOptions = "rw,noexec,nosuid,nodev,mode=1777" DefaultTmpSize = "64m" DefaultRunSize = "16m" DefaultAppArmor = "docker-default" DefaultStopTimeout = 15 NoNewPrivileges = "no-new-privileges:true" )
Hardening defaults (CIS Docker Benchmark / OWASP Docker Top 10).
Variables ¶
var AllowedCapAdd = map[string]bool{ "NET_BIND_SERVICE": true, "CHOWN": true, "SETUID": true, "SETGID": true, }
AllowedCapAdd is the only set of capabilities an app profile may add back after cap_drop ALL.
var Allowlist = []Rule{ rule(http.MethodGet, `/_ping`, "liveness + API version negotiation"), rule(http.MethodHead, `/_ping`, "liveness"), rule(http.MethodGet, `/version`, "API version negotiation"), rule(http.MethodGet, `/info`, "self-audit: daemon configuration"), rule(http.MethodGet, `/events`, "container lifecycle events"), rule(http.MethodGet, `/system/df`, "disk usage in the UI"), rule(http.MethodGet, `/containers/json`, "list managed containers"), rule(http.MethodPost, `/containers/create`, "create hardened containers (HostConfig built by this package)"), rule(http.MethodGet, `/containers/`+idPat+`/json`, "inspect (health, hardening verification)"), rule(http.MethodGet, `/containers/`+idPat+`/logs`, "deploy/app logs"), rule(http.MethodGet, `/containers/`+idPat+`/stats`, "resource usage in the UI"), rule(http.MethodPost, `/containers/`+idPat+`/start`, "start"), rule(http.MethodPost, `/containers/`+idPat+`/stop`, "stop"), rule(http.MethodPost, `/containers/`+idPat+`/restart`, "restart"), rule(http.MethodPost, `/containers/`+idPat+`/kill`, "kill after stop timeout"), rule(http.MethodPost, `/containers/`+idPat+`/wait`, "wait for one-shot jobs (backups, scans)"), rule(http.MethodDelete, `/containers/`+idPat, "remove"), rule(http.MethodGet, `/images/json`, "list images"), rule(http.MethodPost, `/images/create`, "pull"), rule(http.MethodPost, `/images/load`, "load BuildKit output tarball"), rule(http.MethodGet, `/images/`+imgPat+`/json`, "inspect image (USER, ports)"), rule(http.MethodGet, `/images/get`, "export image tarball for scanning (?names=)"), rule(http.MethodPost, `/images/`+imgPat+`/tag`, "tag releases"), rule(http.MethodDelete, `/images/`+imgPat, "prune old releases"), rule(http.MethodGet, `/networks`, "list networks"), rule(http.MethodGet, `/networks/`+idPat, "inspect network"), rule(http.MethodPost, `/networks/create`, "per-app networks"), rule(http.MethodPost, `/networks/`+idPat+`/connect`, "attach Traefik to an app network"), rule(http.MethodPost, `/networks/`+idPat+`/disconnect`, "detach Traefik"), rule(http.MethodDelete, `/networks/`+idPat, "remove app network"), rule(http.MethodGet, `/volumes`, "list volumes"), rule(http.MethodGet, `/volumes/`+idPat, "inspect volume"), rule(http.MethodPost, `/volumes/create`, "addon data volumes"), rule(http.MethodDelete, `/volumes/`+idPat, "remove addon data volumes"), }
Allowlist is the exhaustive set of (method, path) pairs platformd may call.
Deliberately ABSENT (and covered by TestAllowlistDeniesDangerousEndpoints): exec (any form), attach, archive (file copy in/out), export, commit, build (we use a separate rootless BuildKit), update/rename/resize, plugins, swarm/nodes/services/tasks, secrets/configs, session, auth, distribution, grpc.
var ErrForbidden = errors.New("forbidden by hardening policy")
ErrForbidden is wrapped by every validation failure that would violate a golden rule.
var SeccompDefaultProfile string
SeccompDefaultProfile is Moby's default seccomp profile, shipped with the binary so that it is applied explicitly and verifiably (docker inspect shows it) on every host, including daemons whose configured default is "unconfined" (D-005). install/profiles/seccomp-default.json is a byte-identical copy for operators; TestSeccompProfileCopiesInSync keeps them in lock-step.
Functions ¶
func AppContainerName ¶
AppContainerName returns the container name for a release of an app.
func AppNetworkName ¶
AppNetworkName returns the per-app network name for an app.
func CopyLogs ¶
CopyLogs demultiplexes a Docker log stream (stdout/stderr frames for non-TTY containers) into w, interleaving both streams. Callers redact before exposing the output.
func IsRootUser ¶
IsRootUser reports whether a user string designates uid 0.
func NormalizePath ¶
NormalizePath strips the optional /v1.xx API version prefix and cleans the path. It returns ok=false for paths that are not in canonical form (traversal, double slashes, trailing slash) so that callers reject them before matching.
func ValidateAppName ¶
ValidateAppName reports whether name is a valid app name (lowercase DNS-label style).
func VerifyHardened ¶
func VerifyHardened(insp container.InspectResponse) []string
VerifyHardened checks an inspected container against the golden-rule defaults. It is used by the integration tests AND by the self-audit command, so that what we test is what we ship.
Types ¶
type Built ¶
type Built struct {
Name string
Config *container.Config
HostConfig *container.HostConfig
Networking *network.NetworkingConfig
Warnings []Warning
}
Built is the result of Build: the exact structs passed to ContainerCreate plus the warnings produced by overrides.
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is the platform's typed wrapper around the Docker Engine API. Every call is a typed SDK call (golden rule 1) addressed to the socket-proxy (golden rule 2). It never shells out and never exposes the raw SDK client to callers.
func New ¶
New connects to the Docker Engine API at host, e.g. "tcp://socket-proxy:2375" in production or "unix:///var/run/docker.sock" in integration tests.
func (*Client) ConnectContainer ¶
ConnectContainer attaches a container to a network (idempotent).
func (*Client) Create ¶
Create builds the hardened configuration from spec and creates the container (not started).
func (*Client) CreateAndStart ¶
CreateAndStart is Create followed by Start; on start failure the container is removed.
func (*Client) DisconnectContainer ¶
DisconnectContainer detaches a container from a network (idempotent).
func (*Client) EnsureNetwork ¶
EnsureNetwork creates the named bridge network if it does not exist and returns its ID. internal networks have no external connectivity (addons that need no egress).
func (*Client) ImageExists ¶
ImageExists reports whether the image is present locally.
func (*Client) ListManaged ¶
ListManaged lists containers created by the platform, optionally filtered to one app.
func (*Client) Logs ¶
func (c *Client) Logs(ctx context.Context, id string, follow bool, tail string) (io.ReadCloser, error)
Logs streams container logs. Callers must redact secrets before exposing the stream.
func (*Client) PullImage ¶
PullImage pulls an image and drains the progress stream. Progress is discarded, not logged.
func (*Client) RemoveImage ¶
RemoveImage deletes an image reference; missing images are not an error.
func (*Client) RemoveNetwork ¶
RemoveNetwork deletes a network; missing networks are not an error.
func (*Client) RemoveVolume ¶
RemoveVolume deletes a named volume; missing volumes are not an error.
func (*Client) SaveImage ¶
SaveImage exports an image as a tarball (for scanning in an isolated container).
type ContainerSpec ¶
type ContainerSpec struct {
Name string
Image string
Kind string
App string // owning app (nameRe); used for the per-app network and labels
// Release is a free-form release identifier stored in a label.
Release string
Cmd []string
Entrypoint []string
Env []string // secrets are injected here at runtime; never logged
Labels map[string]string
WorkingDir string
// User is "uid[:gid]". Empty selects DefaultUser. Root requires Overrides.AllowRoot.
User string
// Network is the per-app network name the container joins (required unless NoNetwork).
Network string
// NoNetwork attaches the container to the "none" network (one-shot jobs that need no I/O).
NoNetwork bool
// Aliases are extra DNS names on Network.
Aliases []string
// ExposedPort is documented for the router; it is never published on the host.
ExposedPort int
MemoryBytes int64
NanoCPUs int64
PidsLimit int64
CapAdd []string // subset of AllowedCapAdd
Mounts []Mount
// ExtraTmpfs adds tmpfs mounts (path -> size) in addition to /tmp and /run.
ExtraTmpfs map[string]string
// OneShot containers (jobs) do not restart and are removed after they exit.
OneShot bool
// DataDir is the platform data directory; bind mounts must live under it.
DataDir string
// HostDataDir is where the daemon sees DataDir. platformd runs in a container with the data
// directory bind-mounted at DataDir, but the daemon resolves bind sources on the host, so
// sources under DataDir are rewritten to HostDataDir (empty or equal = no translation).
HostDataDir string
// AppArmorProfile overrides the AppArmor profile name (default docker-default).
AppArmorProfile string
// Healthcheck is passed through untouched (typed).
Healthcheck *container.HealthConfig
// Test marks containers created by the test-suite (label redoubt.test=1) so cleanup can
// find them and nothing else on a developer machine is ever touched.
Test bool
Overrides Overrides
}
ContainerSpec is the platform's typed description of a container. It is the ONLY way platform code creates containers; Build() turns it into Docker SDK structs with every hardening default applied. There is no way to express Privileged, host networking, port publishing, or a Docker-socket mount.
func (ContainerSpec) Build ¶
func (s ContainerSpec) Build() (*Built, error)
Build validates the spec and returns the hardened Docker SDK structures.
type Mount ¶
type Mount struct {
// Source is a named volume (Type=volume) or an absolute host path (Type=bind).
Source string
Target string
ReadOnly bool
Type mount.Type
}
Mount is a validated volume/bind mount. Only named volumes and bind mounts under the platform data directory are permitted; the Docker socket and other host paths are refused.
type Option ¶
type Option func(*options)
Option configures New.
func WithHTTPClient ¶
WithHTTPClient supplies a custom HTTP client (tests use it with a Recorder transport).
type Overrides ¶
type Overrides struct {
// AllowRoot permits User to be root (uid 0). Strongly discouraged.
AllowRoot bool
// WritableRootFS disables the read-only root filesystem.
WritableRootFS bool
// ExecutableTmp drops noexec from the /tmp tmpfs (some runtimes JIT into /tmp).
ExecutableTmp bool
}
Overrides are the explicit, audited escape hatches. Every non-zero field weakens a default and produces a Warning that the caller MUST surface to the user and write to the audit log.
type Recorder ¶
type Recorder struct {
Base http.RoundTripper
// contains filtered or unexported fields
}
Recorder is an http.RoundTripper that records every request the SDK issues.
type Rule ¶
Rule is one entry of the least-privilege Docker Engine API allow-list.
The allow-list is the single source of truth for what the control plane may ask the Docker daemon to do. It is enforced twice: by cmd/socket-proxy (the only process holding /var/run/docker.sock) and by the client-drift test in this package, which fails if the SDK wrapper ever issues a request the proxy would reject.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package dockertest provides a minimal fake Docker Engine API for unit tests in other packages.
|
Package dockertest provides a minimal fake Docker Engine API for unit tests in other packages. |