Skip to content

Commit 0688013

Browse files
tonistiigicrazy-max
authored andcommitted
add autoallow and entitlements support to CDI devices
Devices can be marked as "automatically allowed" by TOML config or by the CDI spec of specific file via annotation. Device that is is not "automatically allowed" needs to be allowed by the build request by passing entitlement. For example a Dockerfile may not use a device without use invoking the build permitting it. --allow device grants access to any device. --allow device=kind|name grants access to specific device. --allow device=kind|name,alias=kind|name allows mapping kind to a specific device or one device to another. Alias is the name requested by the build and device is the actual device that is being enabled. Signed-off-by: Tonis Tiigi <[email protected]>
1 parent a20ae4e commit 0688013

File tree

20 files changed

+316
-95
lines changed

20 files changed

+316
-95
lines changed

client/build_test.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1838,7 +1838,7 @@ func testClientGatewayContainerSecurityMode(t *testing.T, sb integration.Sandbox
18381838

18391839
command := []string{"sh", "-c", `cat /proc/self/status | grep CapEff | cut -f 2`}
18401840
mode := llb.SecurityModeSandbox
1841-
var allowedEntitlements []entitlements.Entitlement
1841+
var allowedEntitlements []string
18421842
var assertCaps func(caps uint64)
18431843
secMode := sb.Value("secmode")
18441844
if secMode == securitySandbox {
@@ -1850,7 +1850,7 @@ func testClientGatewayContainerSecurityMode(t *testing.T, sb integration.Sandbox
18501850
*/
18511851
require.Equal(t, uint64(0xa80425fb), caps)
18521852
}
1853-
allowedEntitlements = []entitlements.Entitlement{}
1853+
allowedEntitlements = []string{}
18541854
if expectFail {
18551855
return
18561856
}
@@ -1869,9 +1869,9 @@ func testClientGatewayContainerSecurityMode(t *testing.T, sb integration.Sandbox
18691869
require.Equal(t, uint64(0x3fffffffff), caps&0x3fffffffff)
18701870
}
18711871
mode = llb.SecurityModeInsecure
1872-
allowedEntitlements = []entitlements.Entitlement{entitlements.EntitlementSecurityInsecure}
1872+
allowedEntitlements = []string{entitlements.EntitlementSecurityInsecure.String()}
18731873
if expectFail {
1874-
allowedEntitlements = []entitlements.Entitlement{}
1874+
allowedEntitlements = []string{}
18751875
}
18761876
}
18771877

@@ -2046,13 +2046,13 @@ func testClientGatewayContainerHostNetworking(t *testing.T, sb integration.Sandb
20462046
ctx := sb.Context()
20472047
product := "buildkit_test"
20482048

2049-
var allowedEntitlements []entitlements.Entitlement
2049+
var allowedEntitlements []string
20502050
netMode := pb.NetMode_UNSET
20512051
if sb.Value("netmode") == hostNetwork {
20522052
netMode = pb.NetMode_HOST
2053-
allowedEntitlements = []entitlements.Entitlement{entitlements.EntitlementNetworkHost}
2053+
allowedEntitlements = []string{entitlements.EntitlementNetworkHost.String()}
20542054
if expectFail {
2055-
allowedEntitlements = []entitlements.Entitlement{}
2055+
allowedEntitlements = []string{}
20562056
}
20572057
}
20582058
c, err := New(sb.Context(), sb.Address())

client/client_test.go

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -400,9 +400,9 @@ func testHostNetworking(t *testing.T, sb integration.Sandbox) {
400400
t.SkipNow()
401401
}
402402
netMode := sb.Value("netmode")
403-
var allowedEntitlements []entitlements.Entitlement
403+
var allowedEntitlements []string
404404
if netMode == hostNetwork {
405-
allowedEntitlements = []entitlements.Entitlement{entitlements.EntitlementNetworkHost}
405+
allowedEntitlements = []string{entitlements.EntitlementNetworkHost.String()}
406406
}
407407
c, err := New(sb.Context(), sb.Address())
408408
require.NoError(t, err)
@@ -1063,7 +1063,7 @@ func testSecurityMode(t *testing.T, sb integration.Sandbox) {
10631063
workers.CheckFeatureCompat(t, sb, workers.FeatureSecurityMode)
10641064
command := `sh -c 'cat /proc/self/status | grep CapEff | cut -f 2 > /out'`
10651065
mode := llb.SecurityModeSandbox
1066-
var allowedEntitlements []entitlements.Entitlement
1066+
var allowedEntitlements []string
10671067
var assertCaps func(caps uint64)
10681068
secMode := sb.Value("secmode")
10691069
if secMode == securitySandbox {
@@ -1075,7 +1075,7 @@ func testSecurityMode(t *testing.T, sb integration.Sandbox) {
10751075
*/
10761076
require.Equal(t, uint64(0xa80425fb), caps)
10771077
}
1078-
allowedEntitlements = []entitlements.Entitlement{}
1078+
allowedEntitlements = []string{}
10791079
} else {
10801080
assertCaps = func(caps uint64) {
10811081
/*
@@ -1091,7 +1091,7 @@ func testSecurityMode(t *testing.T, sb integration.Sandbox) {
10911091
require.Equal(t, uint64(0x3fffffffff), caps&0x3fffffffff)
10921092
}
10931093
mode = llb.SecurityModeInsecure
1094-
allowedEntitlements = []entitlements.Entitlement{entitlements.EntitlementSecurityInsecure}
1094+
allowedEntitlements = []string{entitlements.EntitlementSecurityInsecure.String()}
10951095
}
10961096

10971097
c, err := New(sb.Context(), sb.Address())
@@ -1138,13 +1138,13 @@ func testSecurityModeSysfs(t *testing.T, sb integration.Sandbox) {
11381138
}
11391139

11401140
mode := llb.SecurityModeSandbox
1141-
var allowedEntitlements []entitlements.Entitlement
1141+
var allowedEntitlements []string
11421142
secMode := sb.Value("secmode")
11431143
if secMode == securitySandbox {
1144-
allowedEntitlements = []entitlements.Entitlement{}
1144+
allowedEntitlements = []string{}
11451145
} else {
11461146
mode = llb.SecurityModeInsecure
1147-
allowedEntitlements = []entitlements.Entitlement{entitlements.EntitlementSecurityInsecure}
1147+
allowedEntitlements = []string{entitlements.EntitlementSecurityInsecure.String()}
11481148
}
11491149

11501150
c, err := New(sb.Context(), sb.Address())
@@ -1191,7 +1191,7 @@ func testSecurityModeErrors(t *testing.T, sb integration.Sandbox) {
11911191
require.NoError(t, err)
11921192

11931193
_, err = c.Solve(sb.Context(), def, SolveOpt{
1194-
AllowedEntitlements: []entitlements.Entitlement{entitlements.EntitlementSecurityInsecure},
1194+
AllowedEntitlements: []string{entitlements.EntitlementSecurityInsecure.String()},
11951195
}, nil)
11961196
require.Error(t, err)
11971197
require.Contains(t, err.Error(), "security.insecure is not allowed")
@@ -11054,22 +11054,26 @@ func testCDI(t *testing.T, sb integration.Sandbox) {
1105411054
defer c.Close()
1105511055

1105611056
require.NoError(t, os.WriteFile(filepath.Join(sb.CDISpecDir(), "vendor1-device.yaml"), []byte(`
11057-
cdiVersion: "0.3.0"
11057+
cdiVersion: "0.6.0"
1105811058
kind: "vendor1.com/device"
1105911059
devices:
1106011060
- name: foo
1106111061
containerEdits:
1106211062
env:
1106311063
- FOO=injected
11064+
annotations:
11065+
org.mobyproject.buildkit.device.autoallow: true
1106411066
`), 0600))
1106511067
require.NoError(t, os.WriteFile(filepath.Join(sb.CDISpecDir(), "vendor2-device.yaml"), []byte(`
11066-
cdiVersion: "0.3.0"
11068+
cdiVersion: "0.6.0"
1106711069
kind: "vendor2.com/device"
1106811070
devices:
1106911071
- name: bar
1107011072
containerEdits:
1107111073
env:
1107211074
- BAR=injected
11075+
annotations:
11076+
org.mobyproject.buildkit.device.autoallow: true
1107311077
`), 0600))
1107411078

1107511079
busybox := llb.Image("busybox:latest")
@@ -11119,7 +11123,7 @@ func testCDIFirst(t *testing.T, sb integration.Sandbox) {
1111911123
defer c.Close()
1112011124

1112111125
require.NoError(t, os.WriteFile(filepath.Join(sb.CDISpecDir(), "vendor1-device.yaml"), []byte(`
11122-
cdiVersion: "0.3.0"
11126+
cdiVersion: "0.6.0"
1112311127
kind: "vendor1.com/device"
1112411128
devices:
1112511129
- name: foo
@@ -11138,6 +11142,8 @@ devices:
1113811142
containerEdits:
1113911143
env:
1114011144
- QUX=injected
11145+
annotations:
11146+
org.mobyproject.buildkit.device.autoallow: true
1114111147
`), 0600))
1114211148

1114311149
busybox := llb.Image("busybox:latest")
@@ -11184,7 +11190,7 @@ func testCDIWildcard(t *testing.T, sb integration.Sandbox) {
1118411190
defer c.Close()
1118511191

1118611192
require.NoError(t, os.WriteFile(filepath.Join(sb.CDISpecDir(), "vendor1-device.yaml"), []byte(`
11187-
cdiVersion: "0.3.0"
11193+
cdiVersion: "0.6.0"
1118811194
kind: "vendor1.com/device"
1118911195
devices:
1119011196
- name: foo
@@ -11195,6 +11201,8 @@ devices:
1119511201
containerEdits:
1119611202
env:
1119711203
- BAR=injected
11204+
annotations:
11205+
org.mobyproject.buildkit.device.autoallow: true
1119811206
`), 0600))
1119911207

1120011208
busybox := llb.Image("busybox:latest")
@@ -11243,6 +11251,7 @@ cdiVersion: "0.6.0"
1124311251
kind: "vendor1.com/device"
1124411252
annotations:
1124511253
foo.bar.baz: FOO
11254+
org.mobyproject.buildkit.device.autoallow: true
1124611255
devices:
1124711256
- name: foo
1124811257
annotations:

client/solve.go

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"io"
88
"maps"
99
"os"
10+
"slices"
1011
"strings"
1112
"time"
1213

@@ -24,7 +25,6 @@ import (
2425
"github.com/moby/buildkit/solver/pb"
2526
spb "github.com/moby/buildkit/sourcepolicy/pb"
2627
"github.com/moby/buildkit/util/bklog"
27-
"github.com/moby/buildkit/util/entitlements"
2828
ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
2929
"github.com/pkg/errors"
3030
"github.com/tonistiigi/fsutil"
@@ -45,7 +45,7 @@ type SolveOpt struct {
4545
CacheExports []CacheOptionsEntry
4646
CacheImports []CacheOptionsEntry
4747
Session []session.Attachable
48-
AllowedEntitlements []entitlements.Entitlement
48+
AllowedEntitlements []string
4949
SharedSession *session.Session // TODO: refactor to better session syncing
5050
SessionPreInitialized bool // TODO: refactor to better session syncing
5151
Internal bool
@@ -277,7 +277,7 @@ func (c *Client) solve(ctx context.Context, def *llb.Definition, runGateway runG
277277
FrontendAttrs: frontendAttrs,
278278
FrontendInputs: frontendInputs,
279279
Cache: &cacheOpt.options,
280-
Entitlements: entitlementsToPB(opt.AllowedEntitlements),
280+
Entitlements: slices.Clone(opt.AllowedEntitlements),
281281
Internal: opt.Internal,
282282
SourcePolicy: opt.SourcePolicy,
283283
})
@@ -553,11 +553,3 @@ func prepareMounts(opt *SolveOpt) (map[string]fsutil.FS, error) {
553553
}
554554
return mounts, nil
555555
}
556-
557-
func entitlementsToPB(entitlements []entitlements.Entitlement) []string {
558-
clone := make([]string, len(entitlements))
559-
for i, e := range entitlements {
560-
clone[i] = string(e)
561-
}
562-
return clone
563-
}

cmd/buildctl/build.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -213,8 +213,7 @@ func buildAction(clicontext *cli.Context) error {
213213
attachable = append(attachable, secretProvider)
214214
}
215215

216-
allowed, err := build.ParseAllow(clicontext.StringSlice("allow"))
217-
if err != nil {
216+
if err := build.ValidateAllow(clicontext.StringSlice("allow")); err != nil {
218217
return err
219218
}
220219

@@ -258,7 +257,7 @@ func buildAction(clicontext *cli.Context) error {
258257
CacheExports: cacheExports,
259258
CacheImports: cacheImports,
260259
Session: attachable,
261-
AllowedEntitlements: allowed,
260+
AllowedEntitlements: clicontext.StringSlice("allow"),
262261
SourcePolicy: srcPol,
263262
Ref: ref,
264263
}

cmd/buildctl/build/allow.go

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,13 @@ import (
44
"github.com/moby/buildkit/util/entitlements"
55
)
66

7-
// ParseAllow parses --allow
8-
func ParseAllow(inp []string) ([]entitlements.Entitlement, error) {
9-
ent := make([]entitlements.Entitlement, 0, len(inp))
7+
// ValidateAllow parses --allow
8+
func ValidateAllow(inp []string) error {
109
for _, v := range inp {
11-
e, err := entitlements.Parse(v)
10+
_, _, err := entitlements.Parse(v)
1211
if err != nil {
13-
return nil, err
12+
return err
1413
}
15-
ent = append(ent, e)
1614
}
17-
return ent, nil
15+
return nil
1816
}

cmd/buildctl/debug/workers.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ func printWorkersVerbose(tw *tabwriter.Writer, winfo []*client.WorkerInfo) {
9494

9595
for _, k := range sortedKeys(d.Annotations) {
9696
v := d.Annotations[k]
97-
fmt.Fprintf(tw, "\t\t%s:\t%s\n", k, v)
97+
fmt.Fprintf(tw, "\tAnnotations:\t%s:\t%s\n", k, v)
9898
}
9999
}
100100
fmt.Fprint(tw, "\n")

cmd/buildkitd/config/config.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,9 @@ type OTELConfig struct {
7777
}
7878

7979
type CDIConfig struct {
80-
Disabled *bool `toml:"disabled"`
81-
SpecDirs []string `toml:"specDirs"`
80+
Disabled *bool `toml:"disabled"`
81+
SpecDirs []string `toml:"specDirs"`
82+
AutoAllowed []string `toml:"autoAllowed"`
8283
}
8384

8485
type GCConfig struct {

cmd/buildkitd/main.go

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import (
3939
"github.com/moby/buildkit/session"
4040
"github.com/moby/buildkit/solver"
4141
"github.com/moby/buildkit/solver/bboltcachestorage"
42+
"github.com/moby/buildkit/solver/llbsolver/cdidevices"
4243
"github.com/moby/buildkit/util/apicaps"
4344
"github.com/moby/buildkit/util/appcontext"
4445
"github.com/moby/buildkit/util/appdefaults"
@@ -846,6 +847,11 @@ func newController(ctx context.Context, c *cli.Context, cfg *config.Config) (*co
846847
"s3": s3remotecache.ResolveCacheImporterFunc(),
847848
"azblob": azblob.ResolveCacheImporterFunc(),
848849
}
850+
851+
if cfg.CDI.Disabled == nil || !*cfg.CDI.Disabled {
852+
cfg.Entitlements = append(cfg.Entitlements, "device")
853+
}
854+
849855
return control.NewController(control.Opt{
850856
SessionManager: sessionManager,
851857
WorkerController: wc,
@@ -1047,16 +1053,16 @@ func newMeterProvider(ctx context.Context) (*sdkmetric.MeterProvider, error) {
10471053
}
10481054

10491055
// getCDIManager returns a new CDI registry with disabled auto-refresh.
1050-
func getCDIManager(disabled *bool, specDirs []string) (*cdi.Cache, error) {
1051-
if disabled != nil && *disabled {
1056+
func getCDIManager(cfg config.CDIConfig) (*cdidevices.Manager, error) {
1057+
if cfg.Disabled != nil && *cfg.Disabled {
10521058
return nil, nil
10531059
}
1054-
if len(specDirs) == 0 {
1055-
return nil, errors.New("No CDI specification directories specified")
1060+
if len(cfg.SpecDirs) == 0 {
1061+
return nil, errors.New("no CDI specification directories specified")
10561062
}
10571063
cdiCache, err := func() (*cdi.Cache, error) {
10581064
cdiCache, err := cdi.NewCache(
1059-
cdi.WithSpecDirs(specDirs...),
1065+
cdi.WithSpecDirs(cfg.SpecDirs...),
10601066
cdi.WithAutoRefresh(false),
10611067
)
10621068
if err != nil {
@@ -1070,5 +1076,5 @@ func getCDIManager(disabled *bool, specDirs []string) (*cdi.Cache, error) {
10701076
if err != nil {
10711077
return nil, errors.Wrapf(err, "CDI registry initialization failure")
10721078
}
1073-
return cdiCache, nil
1079+
return cdidevices.NewManager(cdiCache, cfg.AutoAllowed), nil
10741080
}

cmd/buildkitd/main_containerd_worker.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import (
1212
ctd "github.com/containerd/containerd/v2/client"
1313
"github.com/containerd/containerd/v2/defaults"
1414
"github.com/moby/buildkit/cmd/buildkitd/config"
15-
"github.com/moby/buildkit/solver/llbsolver/cdidevices"
1615
"github.com/moby/buildkit/util/bklog"
1716
"github.com/moby/buildkit/util/disk"
1817
"github.com/moby/buildkit/util/network/cniprovider"
@@ -283,7 +282,7 @@ func containerdWorkerInitializer(c *cli.Context, common workerInitializerOpt) ([
283282

284283
dns := getDNSConfig(common.config.DNS)
285284

286-
cdiManager, err := getCDIManager(common.config.CDI.Disabled, common.config.CDI.SpecDirs)
285+
cdiManager, err := getCDIManager(common.config.CDI)
287286
if err != nil {
288287
return nil, err
289288
}
@@ -345,7 +344,7 @@ func containerdWorkerInitializer(c *cli.Context, common workerInitializerOpt) ([
345344
ParallelismSem: parallelismSem,
346345
TraceSocket: common.traceSocket,
347346
Runtime: runtime,
348-
CDIManager: cdidevices.NewManager(cdiManager),
347+
CDIManager: cdiManager,
349348
}
350349

351350
opt, err := containerd.NewWorkerOpt(workerOpts, ctd.WithTimeout(60*time.Second))

cmd/buildkitd/main_oci_worker.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ func ociWorkerInitializer(c *cli.Context, common workerInitializerOpt) ([]worker
298298

299299
dns := getDNSConfig(common.config.DNS)
300300

301-
cdiManager, err := getCDIManager(common.config.CDI.Disabled, common.config.CDI.SpecDirs)
301+
cdiManager, err := getCDIManager(common.config.CDI)
302302
if err != nil {
303303
return nil, err
304304
}

0 commit comments

Comments
 (0)