Documentation
¶
Overview ¶
Package sandbox manages the isolated Docker environment in which a restored PostgreSQL database is started and validated.
Index ¶
- Constants
- func AllPassed(results []AuditResult) bool
- func ArtifactPathInContainer(hostPath string) string
- func CreateInternalNetwork(ctx context.Context, cli *client.Client, runID string) (string, error)
- func CreatePGDataVolume(ctx context.Context, cli *client.Client, runID string) (string, error)
- func InspectArchive(ctx context.Context, cli *client.Client, cfg InspectConfig) error
- func StartContainer(ctx context.Context, cli *client.Client, c *Container) error
- func Summary(results []AuditResult) string
- type AuditResult
- type Container
- type ContainerConfig
- type InspectConfig
- type Registry
- type Resource
- type ResourceKind
Constants ¶
const ArtifactMountDir = "/restorelab/artifact"
ArtifactMountDir is the directory inside the container where the parent directory of the restored artifact is bind-mounted read-only. The artifact itself is accessible at ArtifactMountDir/<basename>.
const ContainerNamePrefix = "restorelab-postgres-"
ContainerNamePrefix is prepended to every sandbox container name.
const InspectionNamePrefix = "restorelab-inspect-"
InspectionNamePrefix is prepended to inspection container names.
const NetworkCleanupTimeout = 30 * time.Second
NetworkCleanupTimeout is the deadline for network removal.
const NetworkNamePrefix = "restorelab-"
NetworkNamePrefix is prepended to every sandbox network name so stray networks can be identified easily.
const VolumeNamePrefix = "restorelab-"
VolumeNamePrefix is prepended to every sandbox volume name.
Variables ¶
This section is empty.
Functions ¶
func AllPassed ¶
func AllPassed(results []AuditResult) bool
AllPassed reports whether every AuditResult passed.
func ArtifactPathInContainer ¶
ArtifactPathInContainer returns the absolute path of hostPath as seen from inside the sandbox container.
func CreateInternalNetwork ¶
CreateInternalNetwork creates a Docker network with Internal=true so containers attached to it cannot reach the outside world. It returns the network ID.
Note: internal=true prevents egress through the default gateway but does NOT prevent DNS queries via the host resolver on unpatched Docker Engine versions. See CVE-2024-29018.
func CreatePGDataVolume ¶
CreatePGDataVolume creates a temporary volume to hold PGDATA. Using a volume (rather than tmpfs) is essential: tmpfs would keep the entire database in RAM, which is impractical for datasets larger than memory.
The volume is registered in the cleanup registry by the caller.
func InspectArchive ¶
InspectArchive runs `pg_restore --list` on the artifact using a disposable container built from the same image as the sandbox.
The container is deliberately minimal and hostile to the archive:
- no network (NetworkMode = "none")
- no writable volume
- readonly rootfs
- one read-only bind mount of the artifact's parent directory
- cap_drop = ALL
- one tmpfs (/tmp) for any transient files pg_restore may need
The container is removed unconditionally when this function returns, whether the check succeeded or failed.
This implements Design Document v2.0.0 step 12: fail-fast on structurally broken archives before allocating the full sandbox.
func StartContainer ¶
StartContainer starts a previously-created sandbox container.
func Summary ¶
func Summary(results []AuditResult) string
Summary returns a one-line summary of the audit results. For any failed check, the summary includes the check's Details string so operators can see exactly what went wrong without opening the full report.
Types ¶
type AuditResult ¶
AuditResult is the outcome of a single isolation property check.
func AuditContainer ¶
func AuditContainer(ctx context.Context, cli *client.Client, containerID, expectedNetwork string) ([]AuditResult, error)
AuditContainer inspects a running container and verifies each isolation invariant required by the RestoreLab design document (sections 10-12):
- no published ports
- exactly one network, matching expectedNetwork
- no Docker socket bind
- no read-write bind mounts
- ReadonlyRootfs = true
- privileged = false
- "no-new-privileges" present in SecurityOpt
- CapDrop contains "ALL"
- CapAdd is exactly the expected minimal set
- Memory limit is set (> 0)
- PidsLimit is set (> 0)
It returns one AuditResult per property, in a stable order.
type Container ¶
type Container struct {
ID string
Name string
NetworkName string
// ArtifactPathInContainer is the path where the artifact is
// accessible inside the container. Empty if no artifact was
// mounted.
ArtifactPathInContainer string
}
Container is a handle to a running sandbox container.
func CreatePostgresContainer ¶
func CreatePostgresContainer(ctx context.Context, cli *client.Client, cfg ContainerConfig) (*Container, error)
CreatePostgresContainer creates (but does not start) a hardened PostgreSQL container attached to the internal network.
Security properties enforced here:
- cap_drop=ALL + cap_add=<minimal set>
- no-new-privileges:true
- ReadonlyRootfs=true (writable paths via tmpfs and the volume)
- no published ports (PortBindings=nil, PublishAllPorts=false)
- no privileged mode
- no docker.sock mount
- resource limits: ShmSize, Memory, PidsLimit
- attached only to the internal sandbox network
- artifact bind-mounted read-only (if ArtifactPath is set)
type ContainerConfig ¶
type ContainerConfig struct {
// Image is the pinned-by-digest image reference.
Image string
// RunID uniquely identifies this recovery drill.
RunID string
// NetworkName is the internal network the container joins.
NetworkName string
// PGDataVolume is the volume name mounted at PGDATA.
PGDataVolume string
// ArtifactPath is the absolute path on the host to the
// restored artifact file. When non-empty, its parent
// directory is bind-mounted read-only at ArtifactMountDir
// so pg_restore can read it without any write access.
ArtifactPath string
// Database, Username, Password seed the initial database.
Database string
Username string
Password string
// ShmSize in bytes. Must be > 0 and <= Memory.
ShmSize int64
// Memory limit in bytes. Must be > 0.
Memory int64
// PidsLimit must be > 0.
PidsLimit int64
}
ContainerConfig collects every input needed to create a hardened PostgreSQL container.
func (ContainerConfig) Validate ¶
func (c ContainerConfig) Validate() error
Validate checks that the configuration is internally consistent before we call Docker. This is a defense-in-depth check on top of the contract validator.
type InspectConfig ¶
InspectConfig collects inputs for a one-shot inspection.
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
Registry tracks every Docker resource the sandbox creates so they can all be removed even if the run fails halfway through.
func (*Registry) Add ¶
func (r *Registry) Add(kind ResourceKind, id, name string)
Add records a resource for later cleanup. It is safe to call from any goroutine.
type Resource ¶
type Resource struct {
Kind ResourceKind
ID string
Name string
}
Resource is a single Docker object that must be cleaned up.
type ResourceKind ¶
type ResourceKind string
ResourceKind identifies the type of Docker resource tracked.
const ( KindContainer ResourceKind = "container" KindVolume ResourceKind = "volume" KindNetwork ResourceKind = "network" )