mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-24 20:24:09 +00:00
Use seccomp from security context
This commit is contained in:
parent
f3150c9c8c
commit
bf01fa2f00
@ -150,7 +150,7 @@ func (ds *dockerService) CreateContainer(podSandboxID string, config *runtimeapi
|
|||||||
}
|
}
|
||||||
hc.Resources.Devices = devices
|
hc.Resources.Devices = devices
|
||||||
|
|
||||||
securityOpts, err := ds.getSecurityOpts(config.Metadata.Name, sandboxConfig, securityOptSep)
|
securityOpts, err := ds.getSecurityOpts(config.GetLinux().GetSecurityContext().GetSeccompProfilePath(), securityOptSep)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("failed to generate security options for container %q: %v", config.Metadata.Name, err)
|
return "", fmt.Errorf("failed to generate security options for container %q: %v", config.Metadata.Name, err)
|
||||||
}
|
}
|
||||||
|
@ -588,7 +588,7 @@ func (ds *dockerService) makeSandboxDockerConfig(c *runtimeapi.PodSandboxConfig,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set security options.
|
// Set security options.
|
||||||
securityOpts, err := ds.getSecurityOpts(sandboxContainerName, c, securityOptSep)
|
securityOpts, err := ds.getSecurityOpts(c.GetLinux().GetSecurityContext().GetSeccompProfilePath(), securityOptSep)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to generate sandbox security options for sandbox %q: %v", c.Metadata.Name, err)
|
return nil, fmt.Errorf("failed to generate sandbox security options for sandbox %q: %v", c.Metadata.Name, err)
|
||||||
}
|
}
|
||||||
|
@ -146,7 +146,7 @@ type dockerNetworkHost struct {
|
|||||||
var internalLabelKeys []string = []string{containerTypeLabelKey, containerLogPathLabelKey, sandboxIDLabelKey}
|
var internalLabelKeys []string = []string{containerTypeLabelKey, containerLogPathLabelKey, sandboxIDLabelKey}
|
||||||
|
|
||||||
// NOTE: Anything passed to DockerService should be eventually handled in another way when we switch to running the shim as a different process.
|
// NOTE: Anything passed to DockerService should be eventually handled in another way when we switch to running the shim as a different process.
|
||||||
func NewDockerService(client libdocker.Interface, seccompProfileRoot string, podSandboxImage string, streamingConfig *streaming.Config,
|
func NewDockerService(client libdocker.Interface, podSandboxImage string, streamingConfig *streaming.Config,
|
||||||
pluginSettings *NetworkPluginSettings, cgroupsName string, kubeCgroupDriver string, execHandlerName, dockershimRootDir string, disableSharedPID bool) (DockerService, error) {
|
pluginSettings *NetworkPluginSettings, cgroupsName string, kubeCgroupDriver string, execHandlerName, dockershimRootDir string, disableSharedPID bool) (DockerService, error) {
|
||||||
c := libdocker.NewInstrumentedInterface(client)
|
c := libdocker.NewInstrumentedInterface(client)
|
||||||
checkpointHandler, err := NewPersistentCheckpointHandler(dockershimRootDir)
|
checkpointHandler, err := NewPersistentCheckpointHandler(dockershimRootDir)
|
||||||
@ -165,10 +165,9 @@ func NewDockerService(client libdocker.Interface, seccompProfileRoot string, pod
|
|||||||
}
|
}
|
||||||
|
|
||||||
ds := &dockerService{
|
ds := &dockerService{
|
||||||
seccompProfileRoot: seccompProfileRoot,
|
client: c,
|
||||||
client: c,
|
os: kubecontainer.RealOS{},
|
||||||
os: kubecontainer.RealOS{},
|
podSandboxImage: podSandboxImage,
|
||||||
podSandboxImage: podSandboxImage,
|
|
||||||
streamingRuntime: &streamingRuntime{
|
streamingRuntime: &streamingRuntime{
|
||||||
client: client,
|
client: client,
|
||||||
execHandler: execHandler,
|
execHandler: execHandler,
|
||||||
@ -244,12 +243,11 @@ type DockerService interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type dockerService struct {
|
type dockerService struct {
|
||||||
seccompProfileRoot string
|
client libdocker.Interface
|
||||||
client libdocker.Interface
|
os kubecontainer.OSInterface
|
||||||
os kubecontainer.OSInterface
|
podSandboxImage string
|
||||||
podSandboxImage string
|
streamingRuntime *streamingRuntime
|
||||||
streamingRuntime *streamingRuntime
|
streamingServer streaming.Server
|
||||||
streamingServer streaming.Server
|
|
||||||
|
|
||||||
network *network.PluginManager
|
network *network.PluginManager
|
||||||
// Map of podSandboxID :: network-is-ready
|
// Map of podSandboxID :: network-is-ready
|
||||||
|
@ -30,7 +30,6 @@ import (
|
|||||||
"github.com/blang/semver"
|
"github.com/blang/semver"
|
||||||
dockertypes "github.com/docker/docker/api/types"
|
dockertypes "github.com/docker/docker/api/types"
|
||||||
dockercontainer "github.com/docker/docker/api/types/container"
|
dockercontainer "github.com/docker/docker/api/types/container"
|
||||||
"k8s.io/api/core/v1"
|
|
||||||
runtimeapi "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
runtimeapi "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -38,46 +37,35 @@ func DefaultMemorySwap() int64 {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ds *dockerService) getSecurityOpts(containerName string, sandboxConfig *runtimeapi.PodSandboxConfig, separator rune) ([]string, error) {
|
func (ds *dockerService) getSecurityOpts(seccompProfile string, separator rune) ([]string, error) {
|
||||||
// Apply seccomp options.
|
// Apply seccomp options.
|
||||||
seccompSecurityOpts, err := getSeccompSecurityOpts(containerName, sandboxConfig, ds.seccompProfileRoot, separator)
|
seccompSecurityOpts, err := getSeccompSecurityOpts(seccompProfile, separator)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to generate seccomp security options for container %q: %v", containerName, err)
|
return nil, fmt.Errorf("failed to generate seccomp security options for container: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return seccompSecurityOpts, nil
|
return seccompSecurityOpts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getSeccompDockerOpts(annotations map[string]string, ctrName, profileRoot string) ([]dockerOpt, error) {
|
func getSeccompDockerOpts(seccompProfile string) ([]dockerOpt, error) {
|
||||||
profile, profileOK := annotations[v1.SeccompContainerAnnotationKeyPrefix+ctrName]
|
if seccompProfile == "" || seccompProfile == "unconfined" {
|
||||||
if !profileOK {
|
|
||||||
// try the pod profile
|
|
||||||
profile, profileOK = annotations[v1.SeccompPodAnnotationKey]
|
|
||||||
if !profileOK {
|
|
||||||
// return early the default
|
|
||||||
return defaultSeccompOpt, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if profile == "unconfined" {
|
|
||||||
// return early the default
|
// return early the default
|
||||||
return defaultSeccompOpt, nil
|
return defaultSeccompOpt, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if profile == "docker/default" {
|
if seccompProfile == "docker/default" {
|
||||||
// return nil so docker will load the default seccomp profile
|
// return nil so docker will load the default seccomp profile
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if !strings.HasPrefix(profile, "localhost/") {
|
if !strings.HasPrefix(seccompProfile, "localhost/") {
|
||||||
return nil, fmt.Errorf("unknown seccomp profile option: %s", profile)
|
return nil, fmt.Errorf("unknown seccomp profile option: %s", seccompProfile)
|
||||||
}
|
}
|
||||||
|
|
||||||
name := strings.TrimPrefix(profile, "localhost/") // by pod annotation validation, name is a valid subpath
|
fname := strings.TrimPrefix(seccompProfile, "localhost/") // by pod annotation validation, name is a valid subpath
|
||||||
fname := filepath.Join(profileRoot, filepath.FromSlash(name))
|
file, err := ioutil.ReadFile(filepath.FromSlash(fname))
|
||||||
file, err := ioutil.ReadFile(fname)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("cannot load seccomp profile %q: %v", name, err)
|
return nil, fmt.Errorf("cannot load seccomp profile %q: %v", fname, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
b := bytes.NewBuffer(nil)
|
b := bytes.NewBuffer(nil)
|
||||||
@ -85,16 +73,15 @@ func getSeccompDockerOpts(annotations map[string]string, ctrName, profileRoot st
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// Rather than the full profile, just put the filename & md5sum in the event log.
|
// Rather than the full profile, just put the filename & md5sum in the event log.
|
||||||
msg := fmt.Sprintf("%s(md5:%x)", name, md5.Sum(file))
|
msg := fmt.Sprintf("%s(md5:%x)", fname, md5.Sum(file))
|
||||||
|
|
||||||
return []dockerOpt{{"seccomp", b.String(), msg}}, nil
|
return []dockerOpt{{"seccomp", b.String(), msg}}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// getSeccompSecurityOpts gets container seccomp options from container and sandbox
|
// getSeccompSecurityOpts gets container seccomp options from container security context.
|
||||||
// config, currently from sandbox annotations.
|
|
||||||
// It is an experimental feature and may be promoted to official runtime api in the future.
|
// It is an experimental feature and may be promoted to official runtime api in the future.
|
||||||
func getSeccompSecurityOpts(containerName string, sandboxConfig *runtimeapi.PodSandboxConfig, seccompProfileRoot string, separator rune) ([]string, error) {
|
func getSeccompSecurityOpts(seccompProfile string, separator rune) ([]string, error) {
|
||||||
seccompOpts, err := getSeccompDockerOpts(sandboxConfig.GetAnnotations(), containerName, seccompProfileRoot)
|
seccompOpts, err := getSeccompDockerOpts(seccompProfile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -20,51 +20,32 @@ package dockershim
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"path"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"k8s.io/api/core/v1"
|
|
||||||
|
|
||||||
runtimeapi "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGetSeccompSecurityOpts(t *testing.T) {
|
func TestGetSeccompSecurityOpts(t *testing.T) {
|
||||||
containerName := "bar"
|
|
||||||
makeConfig := func(annotations map[string]string) *runtimeapi.PodSandboxConfig {
|
|
||||||
return makeSandboxConfigWithLabelsAndAnnotations("pod", "ns", "1234", 1, nil, annotations)
|
|
||||||
}
|
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
msg string
|
msg string
|
||||||
config *runtimeapi.PodSandboxConfig
|
seccompProfile string
|
||||||
expectedOpts []string
|
expectedOpts []string
|
||||||
}{{
|
}{{
|
||||||
msg: "No security annotations",
|
msg: "No security annotations",
|
||||||
config: makeConfig(nil),
|
seccompProfile: "",
|
||||||
expectedOpts: []string{"seccomp=unconfined"},
|
expectedOpts: []string{"seccomp=unconfined"},
|
||||||
}, {
|
}, {
|
||||||
msg: "Seccomp unconfined",
|
msg: "Seccomp unconfined",
|
||||||
config: makeConfig(map[string]string{
|
seccompProfile: "unconfined",
|
||||||
v1.SeccompContainerAnnotationKeyPrefix + containerName: "unconfined",
|
expectedOpts: []string{"seccomp=unconfined"},
|
||||||
}),
|
|
||||||
expectedOpts: []string{"seccomp=unconfined"},
|
|
||||||
}, {
|
}, {
|
||||||
msg: "Seccomp default",
|
msg: "Seccomp default",
|
||||||
config: makeConfig(map[string]string{
|
seccompProfile: "docker/default",
|
||||||
v1.SeccompContainerAnnotationKeyPrefix + containerName: "docker/default",
|
expectedOpts: nil,
|
||||||
}),
|
|
||||||
expectedOpts: nil,
|
|
||||||
}, {
|
|
||||||
msg: "Seccomp pod default",
|
|
||||||
config: makeConfig(map[string]string{
|
|
||||||
v1.SeccompPodAnnotationKey: "docker/default",
|
|
||||||
}),
|
|
||||||
expectedOpts: nil,
|
|
||||||
}}
|
}}
|
||||||
|
|
||||||
for i, test := range tests {
|
for i, test := range tests {
|
||||||
opts, err := getSeccompSecurityOpts(containerName, test.config, "test/seccomp/profile/root", '=')
|
opts, err := getSeccompSecurityOpts(test.seccompProfile, '=')
|
||||||
assert.NoError(t, err, "TestCase[%d]: %s", i, test.msg)
|
assert.NoError(t, err, "TestCase[%d]: %s", i, test.msg)
|
||||||
assert.Len(t, opts, len(test.expectedOpts), "TestCase[%d]: %s", i, test.msg)
|
assert.Len(t, opts, len(test.expectedOpts), "TestCase[%d]: %s", i, test.msg)
|
||||||
for _, opt := range test.expectedOpts {
|
for _, opt := range test.expectedOpts {
|
||||||
@ -74,42 +55,30 @@ func TestGetSeccompSecurityOpts(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestLoadSeccompLocalhostProfiles(t *testing.T) {
|
func TestLoadSeccompLocalhostProfiles(t *testing.T) {
|
||||||
containerName := "bar"
|
|
||||||
makeConfig := func(annotations map[string]string) *runtimeapi.PodSandboxConfig {
|
|
||||||
return makeSandboxConfigWithLabelsAndAnnotations("pod", "ns", "1234", 1, nil, annotations)
|
|
||||||
}
|
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
msg string
|
msg string
|
||||||
config *runtimeapi.PodSandboxConfig
|
seccompProfile string
|
||||||
expectedOpts []string
|
expectedOpts []string
|
||||||
expectErr bool
|
expectErr bool
|
||||||
}{{
|
}{{
|
||||||
msg: "Seccomp localhost/test profile",
|
msg: "Seccomp localhost/test profile",
|
||||||
config: makeConfig(map[string]string{
|
seccompProfile: "localhost/fixtures/seccomp/test",
|
||||||
v1.SeccompPodAnnotationKey: "localhost/test",
|
expectedOpts: []string{`seccomp={"foo":"bar"}`},
|
||||||
}),
|
expectErr: false,
|
||||||
expectedOpts: []string{`seccomp={"foo":"bar"}`},
|
|
||||||
expectErr: false,
|
|
||||||
}, {
|
}, {
|
||||||
msg: "Seccomp localhost/sub/subtest profile",
|
msg: "Seccomp localhost/sub/subtest profile",
|
||||||
config: makeConfig(map[string]string{
|
seccompProfile: "localhost/fixtures/seccomp/sub/subtest",
|
||||||
v1.SeccompPodAnnotationKey: "localhost/sub/subtest",
|
expectedOpts: []string{`seccomp={"abc":"def"}`},
|
||||||
}),
|
expectErr: false,
|
||||||
expectedOpts: []string{`seccomp={"abc":"def"}`},
|
|
||||||
expectErr: false,
|
|
||||||
}, {
|
}, {
|
||||||
msg: "Seccomp non-existent",
|
msg: "Seccomp non-existent",
|
||||||
config: makeConfig(map[string]string{
|
seccompProfile: "localhost/fixtures/seccomp/non-existent",
|
||||||
v1.SeccompPodAnnotationKey: "localhost/non-existent",
|
expectedOpts: nil,
|
||||||
}),
|
expectErr: true,
|
||||||
expectedOpts: nil,
|
|
||||||
expectErr: true,
|
|
||||||
}}
|
}}
|
||||||
|
|
||||||
profileRoot := path.Join("fixtures", "seccomp")
|
|
||||||
for i, test := range tests {
|
for i, test := range tests {
|
||||||
opts, err := getSeccompSecurityOpts(containerName, test.config, profileRoot, '=')
|
opts, err := getSeccompSecurityOpts(test.seccompProfile, '=')
|
||||||
if test.expectErr {
|
if test.expectErr {
|
||||||
assert.Error(t, err, fmt.Sprintf("TestCase[%d]: %s", i, test.msg))
|
assert.Error(t, err, fmt.Sprintf("TestCase[%d]: %s", i, test.msg))
|
||||||
continue
|
continue
|
||||||
|
@ -29,7 +29,7 @@ func DefaultMemorySwap() int64 {
|
|||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ds *dockerService) getSecurityOpts(containerName string, sandboxConfig *runtimeapi.PodSandboxConfig, separator rune) ([]string, error) {
|
func (ds *dockerService) getSecurityOpts(seccompProfile string, separator rune) ([]string, error) {
|
||||||
glog.Warningf("getSecurityOpts is unsupported in this build")
|
glog.Warningf("getSecurityOpts is unsupported in this build")
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user