Skip to content

Commit

Permalink
feat: add support for adding linux capabilities
Browse files Browse the repository at this point in the history
This commit adds the configuration to add Linux capabilies to
the container for bubblewrap and docker runners, enabling a declarative
way to do least privilege at both build and test time.
Furthermore, the minimum set of process capabilities in
Bubblewrap container is now the same of Docker default capabilities.

Signed-off-by: Massimiliano Giovagnoli <massimiliano.giovagnoli@chainguard.dev>
  • Loading branch information
maxgio92 committed Dec 19, 2024
1 parent 53a5317 commit 17d15ff
Show file tree
Hide file tree
Showing 10 changed files with 74 additions and 9 deletions.
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ require (
github.com/klauspost/compress v1.17.11
github.com/klauspost/pgzip v1.2.6
github.com/kubescape/go-git-url v0.0.30
github.com/moby/moby v27.4.0+incompatible
github.com/opencontainers/image-spec v1.1.0
github.com/package-url/packageurl-go v0.1.3
github.com/pkg/errors v0.9.1
Expand Down Expand Up @@ -93,6 +94,8 @@ require (
github.com/cloudflare/circl v1.5.0 // indirect
github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78 // indirect
github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be // indirect
github.com/containerd/containerd v1.7.24 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/containerd/stargz-snapshotter/estargz v0.16.2 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect
github.com/cyberphone/json-canonicalization v0.0.0-20231217050601-ba74d44ecf5f // indirect
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78 h1:QVw89YDxXxEe+l8gU8E
github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be h1:J5BL2kskAlV9ckgEsNQXscjIaLiOYiZ75d4e94E6dcQ=
github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be/go.mod h1:mk5IQ+Y0ZeO87b858TlA645sVcEcbiX6YqP98kt+7+w=
github.com/containerd/containerd v1.7.24 h1:zxszGrGjrra1yYJW/6rhm9cJ1ZQ8rkKBR48brqsa7nA=
github.com/containerd/containerd v1.7.24/go.mod h1:7QUzfURqZWCZV7RLNEn1XjUCQLEf0bkaK4GjUaZehxw=
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
github.com/containerd/stargz-snapshotter/estargz v0.16.2 h1:DMcqm1rd1ak2hFghkyHlquacSo+zRe+cysRR3CmSpGk=
Expand Down Expand Up @@ -349,6 +351,8 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/moby v27.4.0+incompatible h1:jGXXZCMAmFZS9pKsQqUt9yAPHOC450PM9lbQYPSQnuc=
github.com/moby/moby v27.4.0+incompatible/go.mod h1:fDXVQ6+S340veQPv35CzDahGBmHsiclFwfEygB/TWMc=
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
Expand Down
6 changes: 6 additions & 0 deletions pkg/build/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -1175,6 +1175,12 @@ func (b *Build) buildWorkspaceConfig(ctx context.Context) *container.Config {
cfg.Memory = b.Configuration.Package.Resources.Memory
cfg.Disk = b.Configuration.Package.Resources.Disk
}
if b.Configuration.Capabilities.Add != nil {
cfg.Capabilities.CapAdd = b.Configuration.Capabilities.Add
}
if b.Configuration.Capabilities.Drop != nil {
cfg.Capabilities.CapDrop = b.Configuration.Capabilities.Drop
}

for k, v := range b.Configuration.Environment.Environment {
cfg.Environment[k] = v
Expand Down
6 changes: 6 additions & 0 deletions pkg/build/test.go
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,12 @@ func (t *Test) buildWorkspaceConfig(ctx context.Context, imgRef, pkgName string,
Environment: map[string]string{},
RunAs: imgcfg.Accounts.RunAs,
}
if t.Configuration.Capabilities.Add != nil {
cfg.Capabilities.CapAdd = t.Configuration.Capabilities.Add
}
if t.Configuration.Capabilities.Drop != nil {
cfg.Capabilities.CapDrop = t.Configuration.Capabilities.Drop
}

for k, v := range imgcfg.Environment {
cfg.Environment[k] = v
Expand Down
12 changes: 11 additions & 1 deletion pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -595,12 +595,22 @@ type Input struct {
Required bool `json:"required,omitempty"`
}

// The root melange configuration
type Capabilities struct {
// Linux process capabilities to add to the pipeline container.
Add []string `json:"add,omitempty" yaml:"add,omitempty"`
// Linux process capabilities to drop from the pipeline container.
Drop []string `json:"drop,omitempty" yaml:"drop,omitempty"`
}

// Configuration is the root melange configuration.
type Configuration struct {
// Package metadata
Package Package `json:"package" yaml:"package"`
// The specification for the packages build environment
Environment apko_types.ImageConfiguration `json:"environment" yaml:"environment"`
// Optional: Linux capabilities configuration to apply to the melange runner.
Capabilities Capabilities `json:"capabilities,omitempty" yaml:"capabilities,omitempty"`

// Required: The list of pipelines that produce the package.
Pipeline []Pipeline `json:"pipeline,omitempty" yaml:"pipeline,omitempty"`
// Optional: The list of subpackages that this package also produces.
Expand Down
21 changes: 14 additions & 7 deletions pkg/config/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,7 @@
"properties": {
"description": {
"type": "string",
"description": "Optional: The human readable description of the input"
"description": "Optional: The human-readable description of the input"
},
"default": {
"type": "string",
Expand Down Expand Up @@ -499,7 +499,7 @@
},
"description": {
"type": "string",
"description": "A human readable description of the package"
"description": "A human-readable description of the package"
},
"url": {
"type": "string",
Expand Down Expand Up @@ -608,6 +608,10 @@
},
"Pipeline": {
"properties": {
"if": {
"type": "string",
"description": "Optional: A condition to evaluate before running the pipeline"
},
"name": {
"type": "string",
"description": "Optional: A user defined name for the pipeline"
Expand All @@ -632,7 +636,7 @@
"$ref": "#/$defs/Pipeline"
},
"type": "array",
"description": "Optional: The list of pipelines to run.\n\nEach pipeline runs in it's own context that is not shared between other\npipelines. To share context between pipelines, nest a pipeline within an\nexisting pipeline. This can be useful when you wish to share common\nconfiguration, such as an alternative `working-directory`."
"description": "Optional: The list of pipelines to run.\n\nEach pipeline runs in its own context that is not shared between other\npipelines. To share context between pipelines, nest a pipeline within an\nexisting pipeline. This can be useful when you wish to share common\nconfiguration, such as an alternative `working-directory`."
},
"inputs": {
"additionalProperties": {
Expand All @@ -649,10 +653,6 @@
"type": "string",
"description": "Optional: Labels to apply to the pipeline"
},
"if": {
"type": "string",
"description": "Optional: A condition to evaluate before running the pipeline"
},
"assertions": {
"$ref": "#/$defs/PipelineAssertions",
"description": "Optional: Assertions to evaluate whether the pipeline was successful"
Expand Down Expand Up @@ -733,6 +733,9 @@
"cpu": {
"type": "string"
},
"cpumodel": {
"type": "string"
},
"memory": {
"type": "string"
},
Expand Down Expand Up @@ -898,6 +901,10 @@
"type": "boolean",
"description": "Indicates that this package should be manually updated, usually taking\ncare over special version numbers"
},
"require-sequential": {
"type": "boolean",
"description": "Indicates that automated pull requests should be merged in order rather than superseding and closing previous unmerged PRs"
},
"shared": {
"type": "boolean",
"description": "Indicate that an update to this package requires an epoch bump of\ndownstream dependencies, e.g. golang, java"
Expand Down
21 changes: 20 additions & 1 deletion pkg/container/bubblewrap_runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,13 @@ import (
"path/filepath"
"strings"

"chainguard.dev/melange/internal/logwriter"

apko_build "chainguard.dev/apko/pkg/build"
apko_types "chainguard.dev/apko/pkg/build/types"
"chainguard.dev/melange/internal/logwriter"
"github.com/chainguard-dev/clog"
v1 "github.com/google/go-containerregistry/pkg/v1"
moby "github.com/moby/moby/oci/caps"
"go.opentelemetry.io/otel"
)

Expand Down Expand Up @@ -126,6 +128,23 @@ func (bw *bubblewrap) cmd(ctx context.Context, cfg *Config, debug bool, envOverr
baseargs = append(baseargs, "--gid", buildUserID)
}

// Add Docker runner-parity kernel capabilities to the container.
for _, c := range moby.DefaultCapabilities() {
baseargs = append(baseargs, "--cap-add", c)
}
// Add additional process kernel capabilities to the container as configured.
if cfg.Capabilities.CapAdd != nil {
for _, c := range cfg.Capabilities.CapAdd {
baseargs = append(baseargs, "--cap-add", c)
}
}
// Drop process kernel capabilities from the container as configured.
if cfg.Capabilities.CapDrop != nil {
for _, c := range cfg.Capabilities.CapDrop {
baseargs = append(baseargs, "--cap-drop", c)
}
}

if !debug {
// This flag breaks job control, which we only care about for --interactive debugging.
// So we usually include it, but if we're about to debug, don't set it.
Expand Down
2 changes: 2 additions & 0 deletions pkg/container/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ type BindMount struct {

type Capabilities struct {
Networking bool
CapAdd []string // List of kernel capabilities to add to the container.
CapDrop []string // List of kernel capabilities to drop from the container.
}

type Config struct {
Expand Down
8 changes: 8 additions & 0 deletions pkg/container/docker/docker_runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,14 @@ func (dk *docker) StartPod(ctx context.Context, cfg *mcontainer.Config) error {
hostConfig := &container.HostConfig{
Mounts: mounts,
}
// Add process kernel capabilities to the container if configured.
if len(cfg.Capabilities.CapAdd) > 0 {
hostConfig.CapAdd = cfg.Capabilities.CapAdd
}
// Drop process kernel capabilities from the container if configured.
if len(cfg.Capabilities.CapDrop) > 0 {
hostConfig.CapDrop = cfg.Capabilities.CapDrop
}

platform := &image_spec.Platform{
Architecture: cfg.Arch.String(),
Expand Down
Binary file modified pkg/sca/testdata/generated/x86_64/shbang-test-1-r1.apk
Binary file not shown.

0 comments on commit 17d15ff

Please sign in to comment.