feat: extend the extension service spec with container security options
We extend the extension service spec with three security options, WithWriteableSysfs, WithMaskedPaths, WithReadonlyPaths Fixes #5411 Signed-off-by: Philipp Sauter <philipp.sauter@siderolabs.com>
This commit is contained in:
parent
850cfba72f
commit
f2d89735fd
2
go.mod
2
go.mod
@ -178,6 +178,7 @@ require (
|
||||
github.com/gogo/googleapis v1.4.0 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/mock v1.6.0 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/google/btree v1.0.1 // indirect
|
||||
github.com/google/gnostic v0.5.7-v3refs // indirect
|
||||
@ -247,6 +248,7 @@ require (
|
||||
github.com/spf13/cast v1.4.1 // indirect
|
||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||
github.com/spf13/viper v1.10.0 // indirect
|
||||
github.com/stretchr/objx v0.2.0 // indirect
|
||||
github.com/subosito/gotenv v1.2.0 // indirect
|
||||
github.com/u-root/uio v0.0.0-20210528114334-82958018845c // indirect
|
||||
github.com/ulikunitz/xz v0.5.8 // indirect
|
||||
|
1
go.sum
1
go.sum
@ -528,6 +528,7 @@ github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt
|
||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
|
||||
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
||||
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
|
12
internal/app/machined/pkg/system/services/export_test.go
Normal file
12
internal/app/machined/pkg/system/services/export_test.go
Normal file
@ -0,0 +1,12 @@
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package services
|
||||
|
||||
import "github.com/containerd/containerd/oci"
|
||||
|
||||
// GetOCIOptions gets all OCI options from an Extension.
|
||||
func (svc *Extension) GetOCIOptions() []oci.SpecOpts {
|
||||
return svc.getOCIOptions()
|
||||
}
|
@ -95,6 +95,37 @@ func (svc *Extension) DependsOn(r runtime.Runtime) []string {
|
||||
return deps
|
||||
}
|
||||
|
||||
func (svc *Extension) getOCIOptions() []oci.SpecOpts {
|
||||
ociOpts := []oci.SpecOpts{
|
||||
oci.WithRootFSPath(filepath.Join(constants.ExtensionServicesRootfsPath, svc.Spec.Name)),
|
||||
oci.WithCgroup(constants.CgroupExtensions),
|
||||
oci.WithMounts(svc.Spec.Container.Mounts),
|
||||
oci.WithHostNamespace(specs.NetworkNamespace),
|
||||
oci.WithSelinuxLabel(""),
|
||||
oci.WithApparmorProfile(""),
|
||||
oci.WithCapabilities(capability.AllGrantableCapabilities()),
|
||||
oci.WithAllDevicesAllowed,
|
||||
}
|
||||
|
||||
if !svc.Spec.Container.Security.WriteableRootfs {
|
||||
ociOpts = append(ociOpts, oci.WithRootFSReadonly())
|
||||
}
|
||||
|
||||
if svc.Spec.Container.Security.WriteableSysfs {
|
||||
ociOpts = append(ociOpts, oci.WithWriteableSysfs)
|
||||
}
|
||||
|
||||
if svc.Spec.Container.Security.MaskedPaths != nil {
|
||||
ociOpts = append(ociOpts, oci.WithMaskedPaths(svc.Spec.Container.Security.MaskedPaths))
|
||||
}
|
||||
|
||||
if svc.Spec.Container.Security.ReadonlyPaths != nil {
|
||||
ociOpts = append(ociOpts, oci.WithReadonlyPaths(svc.Spec.Container.Security.ReadonlyPaths))
|
||||
}
|
||||
|
||||
return ociOpts
|
||||
}
|
||||
|
||||
// Runner implements the Service interface.
|
||||
func (svc *Extension) Runner(r runtime.Runtime) (runner.Runner, error) {
|
||||
args := runner.Args{
|
||||
@ -138,17 +169,7 @@ func (svc *Extension) Runner(r runtime.Runtime) (runner.Runner, error) {
|
||||
runner.WithNamespace(constants.SystemContainerdNamespace),
|
||||
runner.WithContainerdAddress(constants.SystemContainerdAddress),
|
||||
runner.WithEnv(env),
|
||||
runner.WithOCISpecOpts(
|
||||
oci.WithRootFSPath(filepath.Join(constants.ExtensionServicesRootfsPath, svc.Spec.Name)),
|
||||
oci.WithRootFSReadonly(),
|
||||
oci.WithCgroup(constants.CgroupExtensions),
|
||||
oci.WithMounts(svc.Spec.Container.Mounts),
|
||||
oci.WithHostNamespace(specs.NetworkNamespace),
|
||||
oci.WithSelinuxLabel(""),
|
||||
oci.WithApparmorProfile(""),
|
||||
oci.WithCapabilities(capability.AllGrantableCapabilities()),
|
||||
oci.WithAllDevicesAllowed,
|
||||
),
|
||||
runner.WithOCISpecOpts(svc.getOCIOptions()...),
|
||||
runner.WithOOMScoreAdj(-600),
|
||||
),
|
||||
restart.WithType(restartType),
|
||||
|
139
internal/app/machined/pkg/system/services/extension_test.go
Normal file
139
internal/app/machined/pkg/system/services/extension_test.go
Normal file
@ -0,0 +1,139 @@
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package services_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/containerd/containerd/containers"
|
||||
"github.com/containerd/containerd/namespaces"
|
||||
"github.com/containerd/containerd/oci"
|
||||
"github.com/containerd/containerd/snapshots"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/talos-systems/talos/internal/app/machined/pkg/system/services"
|
||||
"github.com/talos-systems/talos/internal/app/machined/pkg/system/services/mocks"
|
||||
extservices "github.com/talos-systems/talos/pkg/machinery/extensions/services"
|
||||
)
|
||||
|
||||
type MockClient struct {
|
||||
controller *gomock.Controller
|
||||
}
|
||||
|
||||
func (c *MockClient) SnapshotService(snapshotterName string) snapshots.Snapshotter {
|
||||
return mocks.NewMockSnapshotter(c.controller)
|
||||
}
|
||||
|
||||
func TestGetOCIOptions(t *testing.T) {
|
||||
mockClient := MockClient{
|
||||
controller: gomock.NewController(t),
|
||||
}
|
||||
defer mockClient.controller.Finish()
|
||||
|
||||
generateOCISpec := func(svc *services.Extension) (*oci.Spec, error) {
|
||||
return oci.GenerateSpec(namespaces.WithNamespace(context.Background(), "testNamespace"), &mockClient, &containers.Container{}, svc.GetOCIOptions()...)
|
||||
}
|
||||
|
||||
t.Run("default configurations are cleared away if user passes empty arrays for MaskedPaths and ReadonlyPaths", func(t *testing.T) {
|
||||
// given
|
||||
svc := &services.Extension{
|
||||
Spec: &extservices.Spec{
|
||||
Container: extservices.Container{
|
||||
Security: extservices.Security{
|
||||
MaskedPaths: []string{},
|
||||
ReadonlyPaths: []string{},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// when
|
||||
spec, err := generateOCISpec(svc)
|
||||
|
||||
// then
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []string{}, spec.Linux.MaskedPaths)
|
||||
assert.Equal(t, []string{}, spec.Linux.ReadonlyPaths)
|
||||
})
|
||||
|
||||
t.Run("default configuration applies if user passes nil for MaskedPaths and ReadonlyPaths", func(t *testing.T) {
|
||||
// given
|
||||
svc := &services.Extension{
|
||||
Spec: &extservices.Spec{
|
||||
Container: extservices.Container{
|
||||
Security: extservices.Security{
|
||||
MaskedPaths: nil,
|
||||
ReadonlyPaths: nil,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// when
|
||||
spec, err := generateOCISpec(svc)
|
||||
|
||||
// then
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []string{
|
||||
"/proc/acpi",
|
||||
"/proc/asound",
|
||||
"/proc/kcore",
|
||||
"/proc/keys",
|
||||
"/proc/latency_stats",
|
||||
"/proc/timer_list",
|
||||
"/proc/timer_stats",
|
||||
"/proc/sched_debug",
|
||||
"/sys/firmware",
|
||||
"/proc/scsi",
|
||||
}, spec.Linux.MaskedPaths)
|
||||
assert.Equal(t, []string{
|
||||
"/proc/bus",
|
||||
"/proc/fs",
|
||||
"/proc/irq",
|
||||
"/proc/sys",
|
||||
"/proc/sysrq-trigger",
|
||||
}, spec.Linux.ReadonlyPaths)
|
||||
})
|
||||
|
||||
t.Run("root fs is readonly unless explicitly enabled", func(t *testing.T) {
|
||||
// given
|
||||
svc := &services.Extension{
|
||||
Spec: &extservices.Spec{
|
||||
Container: extservices.Container{
|
||||
Security: extservices.Security{
|
||||
WriteableRootfs: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// when
|
||||
spec, err := generateOCISpec(svc)
|
||||
|
||||
// then
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, false, spec.Root.Readonly)
|
||||
})
|
||||
|
||||
t.Run("root fs is readonly by default", func(t *testing.T) {
|
||||
// given
|
||||
svc := &services.Extension{
|
||||
Spec: &extservices.Spec{
|
||||
Container: extservices.Container{
|
||||
Security: extservices.Security{},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// when
|
||||
spec, err := generateOCISpec(svc)
|
||||
|
||||
// then
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, true, spec.Root.Readonly)
|
||||
})
|
||||
}
|
249
internal/app/machined/pkg/system/services/mocks/snapshotter.go
Normal file
249
internal/app/machined/pkg/system/services/mocks/snapshotter.go
Normal file
@ -0,0 +1,249 @@
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: ~/go/pkg/mod/github.com/containerd/containerd@v1.6.4/snapshots/snapshotter.go
|
||||
|
||||
// Package mocks is a generated GoMock package.
|
||||
package mocks
|
||||
|
||||
import (
|
||||
context "context"
|
||||
reflect "reflect"
|
||||
|
||||
mount "github.com/containerd/containerd/mount"
|
||||
snapshots "github.com/containerd/containerd/snapshots"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
// MockSnapshotter is a mock of Snapshotter interface.
|
||||
type MockSnapshotter struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockSnapshotterMockRecorder
|
||||
}
|
||||
|
||||
// MockSnapshotterMockRecorder is the mock recorder for MockSnapshotter.
|
||||
type MockSnapshotterMockRecorder struct {
|
||||
mock *MockSnapshotter
|
||||
}
|
||||
|
||||
// NewMockSnapshotter creates a new mock instance.
|
||||
func NewMockSnapshotter(ctrl *gomock.Controller) *MockSnapshotter {
|
||||
mock := &MockSnapshotter{ctrl: ctrl}
|
||||
mock.recorder = &MockSnapshotterMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockSnapshotter) EXPECT() *MockSnapshotterMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// Close mocks base method.
|
||||
func (m *MockSnapshotter) Close() error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Close")
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Close indicates an expected call of Close.
|
||||
func (mr *MockSnapshotterMockRecorder) Close() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockSnapshotter)(nil).Close))
|
||||
}
|
||||
|
||||
// Commit mocks base method.
|
||||
func (m *MockSnapshotter) Commit(ctx context.Context, name, key string, opts ...snapshots.Opt) error {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []interface{}{ctx, name, key}
|
||||
for _, a := range opts {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "Commit", varargs...)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Commit indicates an expected call of Commit.
|
||||
func (mr *MockSnapshotterMockRecorder) Commit(ctx, name, key interface{}, opts ...interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
varargs := append([]interface{}{ctx, name, key}, opts...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Commit", reflect.TypeOf((*MockSnapshotter)(nil).Commit), varargs...)
|
||||
}
|
||||
|
||||
// Mounts mocks base method.
|
||||
func (m *MockSnapshotter) Mounts(ctx context.Context, key string) ([]mount.Mount, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Mounts", ctx, key)
|
||||
ret0, _ := ret[0].([]mount.Mount)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// Mounts indicates an expected call of Mounts.
|
||||
func (mr *MockSnapshotterMockRecorder) Mounts(ctx, key interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Mounts", reflect.TypeOf((*MockSnapshotter)(nil).Mounts), ctx, key)
|
||||
}
|
||||
|
||||
// Prepare mocks base method.
|
||||
func (m *MockSnapshotter) Prepare(ctx context.Context, key, parent string, opts ...snapshots.Opt) ([]mount.Mount, error) {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []interface{}{ctx, key, parent}
|
||||
for _, a := range opts {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "Prepare", varargs...)
|
||||
ret0, _ := ret[0].([]mount.Mount)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// Prepare indicates an expected call of Prepare.
|
||||
func (mr *MockSnapshotterMockRecorder) Prepare(ctx, key, parent interface{}, opts ...interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
varargs := append([]interface{}{ctx, key, parent}, opts...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Prepare", reflect.TypeOf((*MockSnapshotter)(nil).Prepare), varargs...)
|
||||
}
|
||||
|
||||
// Remove mocks base method.
|
||||
func (m *MockSnapshotter) Remove(ctx context.Context, key string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Remove", ctx, key)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Remove indicates an expected call of Remove.
|
||||
func (mr *MockSnapshotterMockRecorder) Remove(ctx, key interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Remove", reflect.TypeOf((*MockSnapshotter)(nil).Remove), ctx, key)
|
||||
}
|
||||
|
||||
// Stat mocks base method.
|
||||
func (m *MockSnapshotter) Stat(ctx context.Context, key string) (snapshots.Info, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Stat", ctx, key)
|
||||
ret0, _ := ret[0].(snapshots.Info)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// Stat indicates an expected call of Stat.
|
||||
func (mr *MockSnapshotterMockRecorder) Stat(ctx, key interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Stat", reflect.TypeOf((*MockSnapshotter)(nil).Stat), ctx, key)
|
||||
}
|
||||
|
||||
// Update mocks base method.
|
||||
func (m *MockSnapshotter) Update(ctx context.Context, info snapshots.Info, fieldpaths ...string) (snapshots.Info, error) {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []interface{}{ctx, info}
|
||||
for _, a := range fieldpaths {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "Update", varargs...)
|
||||
ret0, _ := ret[0].(snapshots.Info)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// Update indicates an expected call of Update.
|
||||
func (mr *MockSnapshotterMockRecorder) Update(ctx, info interface{}, fieldpaths ...interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
varargs := append([]interface{}{ctx, info}, fieldpaths...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Update", reflect.TypeOf((*MockSnapshotter)(nil).Update), varargs...)
|
||||
}
|
||||
|
||||
// Usage mocks base method.
|
||||
func (m *MockSnapshotter) Usage(ctx context.Context, key string) (snapshots.Usage, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Usage", ctx, key)
|
||||
ret0, _ := ret[0].(snapshots.Usage)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// Usage indicates an expected call of Usage.
|
||||
func (mr *MockSnapshotterMockRecorder) Usage(ctx, key interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Usage", reflect.TypeOf((*MockSnapshotter)(nil).Usage), ctx, key)
|
||||
}
|
||||
|
||||
// View mocks base method.
|
||||
func (m *MockSnapshotter) View(ctx context.Context, key, parent string, opts ...snapshots.Opt) ([]mount.Mount, error) {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []interface{}{ctx, key, parent}
|
||||
for _, a := range opts {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "View", varargs...)
|
||||
ret0, _ := ret[0].([]mount.Mount)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// View indicates an expected call of View.
|
||||
func (mr *MockSnapshotterMockRecorder) View(ctx, key, parent interface{}, opts ...interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
varargs := append([]interface{}{ctx, key, parent}, opts...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "View", reflect.TypeOf((*MockSnapshotter)(nil).View), varargs...)
|
||||
}
|
||||
|
||||
// Walk mocks base method.
|
||||
func (m *MockSnapshotter) Walk(ctx context.Context, fn snapshots.WalkFunc, filters ...string) error {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []interface{}{ctx, fn}
|
||||
for _, a := range filters {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "Walk", varargs...)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Walk indicates an expected call of Walk.
|
||||
func (mr *MockSnapshotterMockRecorder) Walk(ctx, fn interface{}, filters ...interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
varargs := append([]interface{}{ctx, fn}, filters...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Walk", reflect.TypeOf((*MockSnapshotter)(nil).Walk), varargs...)
|
||||
}
|
||||
|
||||
// MockCleaner is a mock of Cleaner interface.
|
||||
type MockCleaner struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockCleanerMockRecorder
|
||||
}
|
||||
|
||||
// MockCleanerMockRecorder is the mock recorder for MockCleaner.
|
||||
type MockCleanerMockRecorder struct {
|
||||
mock *MockCleaner
|
||||
}
|
||||
|
||||
// NewMockCleaner creates a new mock instance.
|
||||
func NewMockCleaner(ctrl *gomock.Controller) *MockCleaner {
|
||||
mock := &MockCleaner{ctrl: ctrl}
|
||||
mock.recorder = &MockCleanerMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockCleaner) EXPECT() *MockCleanerMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// Cleanup mocks base method.
|
||||
func (m *MockCleaner) Cleanup(ctx context.Context) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Cleanup", ctx)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Cleanup indicates an expected call of Cleanup.
|
||||
func (mr *MockCleanerMockRecorder) Cleanup(ctx interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Cleanup", reflect.TypeOf((*MockCleaner)(nil).Cleanup), ctx)
|
||||
}
|
@ -40,6 +40,20 @@ type Container struct {
|
||||
Args []string `yaml:"args"`
|
||||
// Volume mounts.
|
||||
Mounts []specs.Mount `yaml:"mounts"`
|
||||
// Security options.
|
||||
Security Security `yaml:"security"`
|
||||
}
|
||||
|
||||
// Security options for containers.
|
||||
type Security struct {
|
||||
// WriteableSysfs makes the '/sys' path writeable in the container namespace if set to true.
|
||||
WriteableSysfs bool `yaml:"writeableSysfs"`
|
||||
// MaskedPaths is a list of paths in the container namespace that should not be readable.
|
||||
MaskedPaths []string `yaml:"maskedPaths"`
|
||||
// ReadonlyPaths is a list of paths in the container namespace that should be read-only.
|
||||
ReadonlyPaths []string `yaml:"readonlyPaths"`
|
||||
// WriteableRootfs
|
||||
WriteableRootfs bool `yaml:"writeableRootfs"`
|
||||
}
|
||||
|
||||
// Dependency describes a service Dependency.
|
||||
|
@ -72,6 +72,21 @@ The section `mounts` uses the standard OCI spec:
|
||||
All requested directories will be mounted into the extension service container mount namespace.
|
||||
If the `source` directory doesn't exist in the host filesystem, it will be created (only for writable paths in the Talos root filesystem).
|
||||
|
||||
#### `container.security`
|
||||
|
||||
The section `security` follows this example:
|
||||
|
||||
```yaml
|
||||
maskedPaths:
|
||||
- "/should/be/masked"
|
||||
readonlyPaths:
|
||||
- "/path/that/should/be/readonly"
|
||||
- "/another/readonly/path"
|
||||
writeableRootfs: true
|
||||
```
|
||||
|
||||
The rootfs is readonly by default unless `writeableRootfs: true` and masked paths will be mounted to /dev/null.
|
||||
|
||||
### `depends`
|
||||
|
||||
The `depends` section describes extension service start dependencies: the service will not be started until all dependencies are met.
|
||||
|
Loading…
x
Reference in New Issue
Block a user