Skip to content

Commit

Permalink
support for device entitlement in build and bake
Browse files Browse the repository at this point in the history
Allow access to CDI Devices in Buildkit v0.20.0+ for
devices that are not automatically allowed to be used by
everyone in BuildKit configuration.

Signed-off-by: Tonis Tiigi <[email protected]>
Signed-off-by: CrazyMax <[email protected]>
  • Loading branch information
tonistiigi authored and crazy-max committed Feb 14, 2025
1 parent ef73c64 commit 0c296fe
Show file tree
Hide file tree
Showing 16 changed files with 205 additions and 55 deletions.
5 changes: 1 addition & 4 deletions bake/bake.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import (
"github.com/moby/buildkit/client"
"github.com/moby/buildkit/client/llb"
"github.com/moby/buildkit/session/auth/authprovider"
"github.com/moby/buildkit/util/entitlements"
"github.com/pkg/errors"
"github.com/zclconf/go-cty/cty"
"github.com/zclconf/go-cty/cty/convert"
Expand Down Expand Up @@ -1434,9 +1433,7 @@ func toBuildOpt(t *Target, inp *Input) (*build.Options, error) {
}
bo.Ulimits = ulimits

for _, ent := range t.Entitlements {
bo.Allow = append(bo.Allow, entitlements.Entitlement(ent))
}
bo.Allow = append(bo.Allow, t.Entitlements...)

return bo, nil
}
Expand Down
8 changes: 4 additions & 4 deletions bake/bake_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1806,8 +1806,8 @@ func TestHCLEntitlements(t *testing.T) {
require.Equal(t, "network.host", m["app"].Entitlements[1])

require.Len(t, bo["app"].Allow, 2)
require.Equal(t, entitlements.EntitlementSecurityInsecure, bo["app"].Allow[0])
require.Equal(t, entitlements.EntitlementNetworkHost, bo["app"].Allow[1])
require.Equal(t, entitlements.EntitlementSecurityInsecure.String(), bo["app"].Allow[0])
require.Equal(t, entitlements.EntitlementNetworkHost.String(), bo["app"].Allow[1])
}

func TestEntitlementsForNetHostCompose(t *testing.T) {
Expand Down Expand Up @@ -1846,7 +1846,7 @@ func TestEntitlementsForNetHostCompose(t *testing.T) {
require.Equal(t, "host", *m["app"].NetworkMode)

require.Len(t, bo["app"].Allow, 1)
require.Equal(t, entitlements.EntitlementNetworkHost, bo["app"].Allow[0])
require.Equal(t, entitlements.EntitlementNetworkHost.String(), bo["app"].Allow[0])
require.Equal(t, "host", bo["app"].NetworkMode)
}

Expand Down Expand Up @@ -1877,7 +1877,7 @@ func TestEntitlementsForNetHost(t *testing.T) {
require.Equal(t, "host", *m["app"].NetworkMode)

require.Len(t, bo["app"].Allow, 1)
require.Equal(t, entitlements.EntitlementNetworkHost, bo["app"].Allow[0])
require.Equal(t, entitlements.EntitlementNetworkHost.String(), bo["app"].Allow[0])
require.Equal(t, "host", bo["app"].NetworkMode)
}

Expand Down
62 changes: 60 additions & 2 deletions bake/entitlements.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@ import (
"github.com/moby/buildkit/util/entitlements"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/tonistiigi/go-csvvalue"
)

type EntitlementKey string

const (
EntitlementKeyNetworkHost EntitlementKey = "network.host"
EntitlementKeySecurityInsecure EntitlementKey = "security.insecure"
EntitlementKeyDevice EntitlementKey = "device"
EntitlementKeyFSRead EntitlementKey = "fs.read"
EntitlementKeyFSWrite EntitlementKey = "fs.write"
EntitlementKeyFS EntitlementKey = "fs"
Expand All @@ -39,13 +41,19 @@ const (
type EntitlementConf struct {
NetworkHost bool
SecurityInsecure bool
Devices *EntitlementsDevicesConf
FSRead []string
FSWrite []string
ImagePush []string
ImageLoad []string
SSH bool
}

type EntitlementsDevicesConf struct {
All bool
Devices map[string]struct{}
}

func ParseEntitlements(in []string) (EntitlementConf, error) {
var conf EntitlementConf
for _, e := range in {
Expand All @@ -59,6 +67,22 @@ func ParseEntitlements(in []string) (EntitlementConf, error) {
default:
k, v, _ := strings.Cut(e, "=")
switch k {
case string(EntitlementKeyDevice):
if v == "" {
conf.Devices = &EntitlementsDevicesConf{All: true}
continue
}
fields, err := csvvalue.Fields(v, nil)
if err != nil {
return EntitlementConf{}, errors.Wrapf(err, "failed to parse device entitlement %q", v)
}
if conf.Devices == nil {
conf.Devices = &EntitlementsDevicesConf{}
}
if conf.Devices.Devices == nil {
conf.Devices.Devices = make(map[string]struct{}, 0)
}
conf.Devices.Devices[fields[0]] = struct{}{}
case string(EntitlementKeyFSRead):
conf.FSRead = append(conf.FSRead, v)
case string(EntitlementKeyFSWrite):
Expand Down Expand Up @@ -95,12 +119,34 @@ func (c EntitlementConf) Validate(m map[string]build.Options) (EntitlementConf,

func (c EntitlementConf) check(bo build.Options, expected *EntitlementConf) error {
for _, e := range bo.Allow {
k, rest, _ := strings.Cut(e, "=")
switch k {
case entitlements.EntitlementDevice.String():
if rest == "" {
if c.Devices == nil || !c.Devices.All {
expected.Devices = &EntitlementsDevicesConf{All: true}
}
continue
}
fields, err := csvvalue.Fields(rest, nil)
if err != nil {
return errors.Wrapf(err, "failed to parse device entitlement %q", rest)
}
if expected.Devices == nil {
expected.Devices = &EntitlementsDevicesConf{}
}
if expected.Devices.Devices == nil {
expected.Devices.Devices = make(map[string]struct{}, 0)
}
expected.Devices.Devices[fields[0]] = struct{}{}
}

switch e {
case entitlements.EntitlementNetworkHost:
case entitlements.EntitlementNetworkHost.String():
if !c.NetworkHost {
expected.NetworkHost = true
}
case entitlements.EntitlementSecurityInsecure:
case entitlements.EntitlementSecurityInsecure.String():
if !c.SecurityInsecure {
expected.SecurityInsecure = true
}
Expand Down Expand Up @@ -187,6 +233,18 @@ func (c EntitlementConf) Prompt(ctx context.Context, isRemote bool, out io.Write
flags = append(flags, string(EntitlementKeySecurityInsecure))
}

if c.Devices != nil {
if c.Devices.All {
msgs = append(msgs, " - Access to CDI devices")
flags = append(flags, string(EntitlementKeyDevice))
} else {
for d := range c.Devices.Devices {
msgs = append(msgs, fmt.Sprintf(" - Access to device %s", d))
flags = append(flags, string(EntitlementKeyDevice)+"="+d)
}
}
}

if c.SSH {
msgsFS = append(msgsFS, " - Forwarding default SSH agent socket")
flagsFS = append(flagsFS, string(EntitlementKeySSH))
Expand Down
20 changes: 10 additions & 10 deletions bake/entitlements_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,8 @@ func TestValidateEntitlements(t *testing.T) {
{
name: "NetworkHostMissing",
opt: build.Options{
Allow: []entitlements.Entitlement{
entitlements.EntitlementNetworkHost,
Allow: []string{
entitlements.EntitlementNetworkHost.String(),
},
},
expected: EntitlementConf{
Expand All @@ -223,8 +223,8 @@ func TestValidateEntitlements(t *testing.T) {
NetworkHost: true,
},
opt: build.Options{
Allow: []entitlements.Entitlement{
entitlements.EntitlementNetworkHost,
Allow: []string{
entitlements.EntitlementNetworkHost.String(),
},
},
expected: EntitlementConf{
Expand All @@ -234,9 +234,9 @@ func TestValidateEntitlements(t *testing.T) {
{
name: "SecurityAndNetworkHostMissing",
opt: build.Options{
Allow: []entitlements.Entitlement{
entitlements.EntitlementNetworkHost,
entitlements.EntitlementSecurityInsecure,
Allow: []string{
entitlements.EntitlementNetworkHost.String(),
entitlements.EntitlementSecurityInsecure.String(),
},
},
expected: EntitlementConf{
Expand All @@ -251,9 +251,9 @@ func TestValidateEntitlements(t *testing.T) {
NetworkHost: true,
},
opt: build.Options{
Allow: []entitlements.Entitlement{
entitlements.EntitlementNetworkHost,
entitlements.EntitlementSecurityInsecure,
Allow: []string{
entitlements.EntitlementNetworkHost.String(),
entitlements.EntitlementSecurityInsecure.String(),
},
},
expected: EntitlementConf{
Expand Down
3 changes: 1 addition & 2 deletions build/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ import (
"github.com/moby/buildkit/solver/errdefs"
"github.com/moby/buildkit/solver/pb"
spb "github.com/moby/buildkit/sourcepolicy/pb"
"github.com/moby/buildkit/util/entitlements"
"github.com/moby/buildkit/util/progress/progresswriter"
"github.com/moby/buildkit/util/tracing"
"github.com/opencontainers/go-digest"
Expand All @@ -63,7 +62,7 @@ type Options struct {
Inputs Inputs

Ref string
Allow []entitlements.Entitlement
Allow []string
Attests map[string]*string
BuildArgs map[string]string
CacheFrom []client.CacheOptionsEntry
Expand Down
2 changes: 1 addition & 1 deletion build/opt.go
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ func toSolveOpt(ctx context.Context, node builder.Node, multiDriver bool, opt *O
switch opt.NetworkMode {
case "host":
so.FrontendAttrs["force-network-mode"] = opt.NetworkMode
so.AllowedEntitlements = append(so.AllowedEntitlements, entitlements.EntitlementNetworkHost)
so.AllowedEntitlements = append(so.AllowedEntitlements, entitlements.EntitlementNetworkHost.String())
case "none":
so.FrontendAttrs["force-network-mode"] = opt.NetworkMode
case "", "default":
Expand Down
2 changes: 1 addition & 1 deletion commands/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -593,7 +593,7 @@ func buildCmd(dockerCli command.Cli, rootOpts *rootOptions, debugConfig *debug.D

flags.StringSliceVar(&options.extraHosts, "add-host", []string{}, `Add a custom host-to-IP mapping (format: "host:ip")`)

flags.StringSliceVar(&options.allow, "allow", []string{}, `Allow extra privileged entitlement (e.g., "network.host", "security.insecure")`)
flags.StringArrayVar(&options.allow, "allow", []string{}, `Allow extra privileged entitlement (e.g., "network.host", "security.insecure")`)

flags.StringArrayVarP(&options.annotations, "annotation", "", []string{}, "Add annotation to the image")

Expand Down
2 changes: 1 addition & 1 deletion docs/reference/buildx_build.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Start a build
| Name | Type | Default | Description |
|:----------------------------------------|:--------------|:----------|:-------------------------------------------------------------------------------------------------------------|
| [`--add-host`](#add-host) | `stringSlice` | | Add a custom host-to-IP mapping (format: `host:ip`) |
| [`--allow`](#allow) | `stringSlice` | | Allow extra privileged entitlement (e.g., `network.host`, `security.insecure`) |
| [`--allow`](#allow) | `stringArray` | | Allow extra privileged entitlement (e.g., `network.host`, `security.insecure`) |
| [`--annotation`](#annotation) | `stringArray` | | Add annotation to the image |
| [`--attest`](#attest) | `stringArray` | | Attestation parameters (format: `type=sbom,generator=image`) |
| [`--build-arg`](#build-arg) | `stringArray` | | Set build-time variables |
Expand Down
2 changes: 1 addition & 1 deletion docs/reference/buildx_debug_build.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Start a build
| Name | Type | Default | Description |
|:--------------------|:--------------|:----------|:-------------------------------------------------------------------------------------------------------------|
| `--add-host` | `stringSlice` | | Add a custom host-to-IP mapping (format: `host:ip`) |
| `--allow` | `stringSlice` | | Allow extra privileged entitlement (e.g., `network.host`, `security.insecure`) |
| `--allow` | `stringArray` | | Allow extra privileged entitlement (e.g., `network.host`, `security.insecure`) |
| `--annotation` | `stringArray` | | Add annotation to the image |
| `--attest` | `stringArray` | | Attestation parameters (format: `type=sbom,generator=image`) |
| `--build-arg` | `stringArray` | | Set build-time variables |
Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -194,3 +194,5 @@ exclude (
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2
)

replace github.com/moby/buildkit => github.com/tonistiigi/buildkit v0.10.0-rc2.0.20250214043642-c9e788c50beb
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -297,8 +297,6 @@ github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/z
github.com/mitchellh/mapstructure v0.0.0-20150613213606-2caf8efc9366/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/moby/buildkit v0.20.0-rc2 h1:QjACghvG0pSAp7dk9aQMYWioDEOljDWyyoUjyg35qfg=
github.com/moby/buildkit v0.20.0-rc2/go.mod h1:kMXf90l/f3zygRK8bYbyetfyzoJYntb6Bpi2VsLfXgQ=
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/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg=
Expand Down Expand Up @@ -441,6 +439,8 @@ github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 h1:kdXcSzyDtse
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
github.com/theupdateframework/notary v0.7.0 h1:QyagRZ7wlSpjT5N2qQAh/pN+DVqgekv4DzbAiAiEL3c=
github.com/theupdateframework/notary v0.7.0/go.mod h1:c9DRxcmhHmVLDay4/2fUYdISnHqbFDGRSlXPO0AhYWw=
github.com/tonistiigi/buildkit v0.10.0-rc2.0.20250214043642-c9e788c50beb h1:uk0jspTfKpsaTGWqWO/MHWGQy4atLlOeJ6zjL7V1OeI=
github.com/tonistiigi/buildkit v0.10.0-rc2.0.20250214043642-c9e788c50beb/go.mod h1:kMXf90l/f3zygRK8bYbyetfyzoJYntb6Bpi2VsLfXgQ=
github.com/tonistiigi/dchapes-mode v0.0.0-20241001053921-ca0759fec205 h1:eUk79E1w8yMtXeHSzjKorxuC8qJOnyXQnLaJehxpJaI=
github.com/tonistiigi/dchapes-mode v0.0.0-20241001053921-ca0759fec205/go.mod h1:3Iuxbr0P7D3zUzBMAZB+ois3h/et0shEz0qApgHYGpY=
github.com/tonistiigi/fsutil v0.0.0-20250113203817-b14e27f4135a h1:EfGw4G0x/8qXWgtcZ6KVaPS+wpWOQMaypczzP8ojkMY=
Expand Down
17 changes: 11 additions & 6 deletions util/buildflags/entitlements.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
package buildflags

import "github.com/moby/buildkit/util/entitlements"
import (
"log"

func ParseEntitlements(in []string) ([]entitlements.Entitlement, error) {
out := make([]entitlements.Entitlement, 0, len(in))
"github.com/moby/buildkit/util/entitlements"
)

func ParseEntitlements(in []string) ([]string, error) {
out := make([]string, 0, len(in))
log.Printf("in: %#v", in)
for _, v := range in {
if v == "" {
continue
}

e, err := entitlements.Parse(v)
if err != nil {
if _, _, err := entitlements.Parse(v); err != nil {
return nil, err
}
out = append(out, e)
out = append(out, v)
}
log.Printf("Parsed entitlements: %v", out)
return out, nil
}
14 changes: 3 additions & 11 deletions vendor/github.com/moby/buildkit/client/solve.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 0c296fe

Please sign in to comment.