Merge pull request #215 from Random-Liu/add-capability-all
Add "ALL" capabilities support.
This commit is contained in:
commit
8569fa366e
@ -28,7 +28,9 @@ import (
|
|||||||
"github.com/opencontainers/runc/libcontainer/devices"
|
"github.com/opencontainers/runc/libcontainer/devices"
|
||||||
runtimespec "github.com/opencontainers/runtime-spec/specs-go"
|
runtimespec "github.com/opencontainers/runtime-spec/specs-go"
|
||||||
"github.com/opencontainers/runtime-tools/generate"
|
"github.com/opencontainers/runtime-tools/generate"
|
||||||
|
"github.com/opencontainers/runtime-tools/validate"
|
||||||
"github.com/opencontainers/selinux/go-selinux/label"
|
"github.com/opencontainers/selinux/go-selinux/label"
|
||||||
|
"github.com/syndtr/gocapability/capability"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
||||||
@ -526,21 +528,58 @@ func setOCILinuxResource(g *generate.Generator, resources *runtime.LinuxContaine
|
|||||||
g.SetProcessOOMScoreAdj(int(resources.GetOomScoreAdj()))
|
g.SetProcessOOMScoreAdj(int(resources.GetOomScoreAdj()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getOCICapabilitiesList returns a list of all available capabilities.
|
||||||
|
func getOCICapabilitiesList() []string {
|
||||||
|
var caps []string
|
||||||
|
for _, cap := range capability.List() {
|
||||||
|
if cap > validate.LastCap() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
caps = append(caps, "CAP_"+strings.ToUpper(cap.String()))
|
||||||
|
}
|
||||||
|
return caps
|
||||||
|
}
|
||||||
|
|
||||||
// setOCICapabilities adds/drops process capabilities.
|
// setOCICapabilities adds/drops process capabilities.
|
||||||
func setOCICapabilities(g *generate.Generator, capabilities *runtime.Capability) error {
|
func setOCICapabilities(g *generate.Generator, capabilities *runtime.Capability) error {
|
||||||
if capabilities == nil {
|
if capabilities == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Capabilities in CRI doesn't have `CAP_` prefix, so add it.
|
// Add/drop all capabilities if "all" is specified, so that
|
||||||
|
// following individual add/drop could still work. E.g.
|
||||||
|
// AddCapabilities: []string{"ALL"}, DropCapabilities: []string{"CHOWN"}
|
||||||
|
// will be all capabilities without `CAP_CHOWN`.
|
||||||
|
if util.InStringSlice(capabilities.GetAddCapabilities(), "ALL") {
|
||||||
|
for _, c := range getOCICapabilitiesList() {
|
||||||
|
if err := g.AddProcessCapability(c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if util.InStringSlice(capabilities.GetDropCapabilities(), "ALL") {
|
||||||
|
for _, c := range getOCICapabilitiesList() {
|
||||||
|
if err := g.DropProcessCapability(c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for _, c := range capabilities.GetAddCapabilities() {
|
for _, c := range capabilities.GetAddCapabilities() {
|
||||||
if err := g.AddProcessCapability("CAP_" + c); err != nil {
|
if strings.ToUpper(c) == "ALL" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// Capabilities in CRI doesn't have `CAP_` prefix, so add it.
|
||||||
|
if err := g.AddProcessCapability("CAP_" + strings.ToUpper(c)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, c := range capabilities.GetDropCapabilities() {
|
for _, c := range capabilities.GetDropCapabilities() {
|
||||||
if err := g.DropProcessCapability("CAP_" + c); err != nil {
|
if strings.ToUpper(c) == "ALL" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err := g.DropProcessCapability("CAP_" + strings.ToUpper(c)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,8 @@ import (
|
|||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
||||||
|
|
||||||
|
"github.com/kubernetes-incubator/cri-containerd/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
func checkMount(t *testing.T, mounts []runtimespec.Mount, src, dest, typ string,
|
func checkMount(t *testing.T, mounts []runtimespec.Mount, src, dest, typ string,
|
||||||
@ -87,10 +89,6 @@ func getCreateContainerTestData() (*runtime.ContainerConfig, *runtime.PodSandbox
|
|||||||
OomScoreAdj: 500,
|
OomScoreAdj: 500,
|
||||||
},
|
},
|
||||||
SecurityContext: &runtime.LinuxContainerSecurityContext{
|
SecurityContext: &runtime.LinuxContainerSecurityContext{
|
||||||
Capabilities: &runtime.Capability{
|
|
||||||
AddCapabilities: []string{"SYS_ADMIN"},
|
|
||||||
DropCapabilities: []string{"CHOWN"},
|
|
||||||
},
|
|
||||||
SupplementalGroups: []int64{1111, 2222},
|
SupplementalGroups: []int64{1111, 2222},
|
||||||
NoNewPrivs: true,
|
NoNewPrivs: true,
|
||||||
},
|
},
|
||||||
@ -134,18 +132,6 @@ func getCreateContainerTestData() (*runtime.ContainerConfig, *runtime.PodSandbox
|
|||||||
assert.EqualValues(t, *spec.Linux.Resources.Memory.Limit, 400)
|
assert.EqualValues(t, *spec.Linux.Resources.Memory.Limit, 400)
|
||||||
assert.EqualValues(t, *spec.Process.OOMScoreAdj, 500)
|
assert.EqualValues(t, *spec.Process.OOMScoreAdj, 500)
|
||||||
|
|
||||||
t.Logf("Check capabilities")
|
|
||||||
assert.Contains(t, spec.Process.Capabilities.Bounding, "CAP_SYS_ADMIN")
|
|
||||||
assert.Contains(t, spec.Process.Capabilities.Effective, "CAP_SYS_ADMIN")
|
|
||||||
assert.Contains(t, spec.Process.Capabilities.Inheritable, "CAP_SYS_ADMIN")
|
|
||||||
assert.Contains(t, spec.Process.Capabilities.Permitted, "CAP_SYS_ADMIN")
|
|
||||||
assert.Contains(t, spec.Process.Capabilities.Ambient, "CAP_SYS_ADMIN")
|
|
||||||
assert.NotContains(t, spec.Process.Capabilities.Bounding, "CAP_CHOWN")
|
|
||||||
assert.NotContains(t, spec.Process.Capabilities.Effective, "CAP_CHOWN")
|
|
||||||
assert.NotContains(t, spec.Process.Capabilities.Inheritable, "CAP_CHOWN")
|
|
||||||
assert.NotContains(t, spec.Process.Capabilities.Permitted, "CAP_CHOWN")
|
|
||||||
assert.NotContains(t, spec.Process.Capabilities.Ambient, "CAP_CHOWN")
|
|
||||||
|
|
||||||
t.Logf("Check supplemental groups")
|
t.Logf("Check supplemental groups")
|
||||||
assert.Contains(t, spec.Process.User.AdditionalGids, uint32(1111))
|
assert.Contains(t, spec.Process.User.AdditionalGids, uint32(1111))
|
||||||
assert.Contains(t, spec.Process.User.AdditionalGids, uint32(2222))
|
assert.Contains(t, spec.Process.User.AdditionalGids, uint32(2222))
|
||||||
@ -183,6 +169,74 @@ func TestGeneralContainerSpec(t *testing.T) {
|
|||||||
specCheck(t, testID, testPid, spec)
|
specCheck(t, testID, testPid, spec)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestContainerCapabilities(t *testing.T) {
|
||||||
|
testID := "test-id"
|
||||||
|
testPid := uint32(1234)
|
||||||
|
config, sandboxConfig, imageConfig, specCheck := getCreateContainerTestData()
|
||||||
|
c := newTestCRIContainerdService()
|
||||||
|
for desc, test := range map[string]struct {
|
||||||
|
capability *runtime.Capability
|
||||||
|
includes []string
|
||||||
|
excludes []string
|
||||||
|
}{
|
||||||
|
"should be able to add/drop capabilities": {
|
||||||
|
capability: &runtime.Capability{
|
||||||
|
AddCapabilities: []string{"SYS_ADMIN"},
|
||||||
|
DropCapabilities: []string{"CHOWN"},
|
||||||
|
},
|
||||||
|
includes: []string{"CAP_SYS_ADMIN"},
|
||||||
|
excludes: []string{"CAP_CHOWN"},
|
||||||
|
},
|
||||||
|
"should be able to add all capabilities": {
|
||||||
|
capability: &runtime.Capability{
|
||||||
|
AddCapabilities: []string{"ALL"},
|
||||||
|
},
|
||||||
|
includes: getOCICapabilitiesList(),
|
||||||
|
},
|
||||||
|
"should be able to drop all capabilities": {
|
||||||
|
capability: &runtime.Capability{
|
||||||
|
DropCapabilities: []string{"ALL"},
|
||||||
|
},
|
||||||
|
excludes: getOCICapabilitiesList(),
|
||||||
|
},
|
||||||
|
"should be able to drop capabilities with add all": {
|
||||||
|
capability: &runtime.Capability{
|
||||||
|
AddCapabilities: []string{"ALL"},
|
||||||
|
DropCapabilities: []string{"CHOWN"},
|
||||||
|
},
|
||||||
|
includes: util.SubstractStringSlice(getOCICapabilitiesList(), "CAP_CHOWN"),
|
||||||
|
excludes: []string{"CAP_CHOWN"},
|
||||||
|
},
|
||||||
|
"should be able to add capabilities with drop all": {
|
||||||
|
capability: &runtime.Capability{
|
||||||
|
AddCapabilities: []string{"SYS_ADMIN"},
|
||||||
|
DropCapabilities: []string{"ALL"},
|
||||||
|
},
|
||||||
|
includes: []string{"CAP_SYS_ADMIN"},
|
||||||
|
excludes: util.SubstractStringSlice(getOCICapabilitiesList(), "CAP_SYS_ADMIN"),
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
t.Logf("TestCase %q", desc)
|
||||||
|
config.Linux.SecurityContext.Capabilities = test.capability
|
||||||
|
spec, err := c.generateContainerSpec(testID, testPid, config, sandboxConfig, imageConfig, nil)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
specCheck(t, testID, testPid, spec)
|
||||||
|
t.Log(spec.Process.Capabilities.Bounding)
|
||||||
|
for _, include := range test.includes {
|
||||||
|
assert.Contains(t, spec.Process.Capabilities.Bounding, include)
|
||||||
|
assert.Contains(t, spec.Process.Capabilities.Effective, include)
|
||||||
|
assert.Contains(t, spec.Process.Capabilities.Inheritable, include)
|
||||||
|
assert.Contains(t, spec.Process.Capabilities.Permitted, include)
|
||||||
|
}
|
||||||
|
for _, exclude := range test.excludes {
|
||||||
|
assert.NotContains(t, spec.Process.Capabilities.Bounding, exclude)
|
||||||
|
assert.NotContains(t, spec.Process.Capabilities.Effective, exclude)
|
||||||
|
assert.NotContains(t, spec.Process.Capabilities.Inheritable, exclude)
|
||||||
|
assert.NotContains(t, spec.Process.Capabilities.Permitted, exclude)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestContainerSpecTty(t *testing.T) {
|
func TestContainerSpecTty(t *testing.T) {
|
||||||
testID := "test-id"
|
testID := "test-id"
|
||||||
testPid := uint32(1234)
|
testPid := uint32(1234)
|
||||||
|
43
pkg/util/strings.go
Normal file
43
pkg/util/strings.go
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2017 The Kubernetes Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package util
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
|
// InStringSlice checks whether a string is inside a string slice.
|
||||||
|
// Comparison is case insensitive.
|
||||||
|
func InStringSlice(ss []string, str string) bool {
|
||||||
|
for _, s := range ss {
|
||||||
|
if strings.ToLower(s) == strings.ToLower(str) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// SubstractStringSlice substracts string from string slice.
|
||||||
|
// Comparison is case insensitive.
|
||||||
|
func SubstractStringSlice(ss []string, str string) []string {
|
||||||
|
var res []string
|
||||||
|
for _, s := range ss {
|
||||||
|
if strings.ToLower(s) == strings.ToLower(str) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
res = append(res, s)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
48
pkg/util/strings_test.go
Normal file
48
pkg/util/strings_test.go
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2017 The Kubernetes Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestInStringSlice(t *testing.T) {
|
||||||
|
ss := []string{"ABC", "def", "ghi"}
|
||||||
|
|
||||||
|
assert.True(t, InStringSlice(ss, "ABC"))
|
||||||
|
assert.True(t, InStringSlice(ss, "abc"))
|
||||||
|
assert.True(t, InStringSlice(ss, "def"))
|
||||||
|
assert.True(t, InStringSlice(ss, "DEF"))
|
||||||
|
assert.False(t, InStringSlice(ss, "hij"))
|
||||||
|
assert.False(t, InStringSlice(ss, "HIJ"))
|
||||||
|
assert.False(t, InStringSlice(nil, "HIJ"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSubstractStringSlice(t *testing.T) {
|
||||||
|
ss := []string{"ABC", "def", "ghi"}
|
||||||
|
|
||||||
|
assert.Equal(t, []string{"def", "ghi"}, SubstractStringSlice(ss, "abc"))
|
||||||
|
assert.Equal(t, []string{"def", "ghi"}, SubstractStringSlice(ss, "ABC"))
|
||||||
|
assert.Equal(t, []string{"ABC", "ghi"}, SubstractStringSlice(ss, "def"))
|
||||||
|
assert.Equal(t, []string{"ABC", "ghi"}, SubstractStringSlice(ss, "DEF"))
|
||||||
|
assert.Equal(t, []string{"ABC", "def", "ghi"}, SubstractStringSlice(ss, "hij"))
|
||||||
|
assert.Equal(t, []string{"ABC", "def", "ghi"}, SubstractStringSlice(ss, "HIJ"))
|
||||||
|
assert.Empty(t, SubstractStringSlice(nil, "hij"))
|
||||||
|
assert.Empty(t, SubstractStringSlice([]string{}, "hij"))
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user