Merge pull request #4700 from mikebrow/cri-security-profile-update
CRI security profile update for CRI graduation
This commit is contained in:
commit
550b4949cb
2
go.mod
2
go.mod
@ -62,7 +62,7 @@ require (
|
|||||||
k8s.io/apiserver v0.19.4
|
k8s.io/apiserver v0.19.4
|
||||||
k8s.io/client-go v0.19.4
|
k8s.io/client-go v0.19.4
|
||||||
k8s.io/component-base v0.19.4
|
k8s.io/component-base v0.19.4
|
||||||
k8s.io/cri-api v0.19.4
|
k8s.io/cri-api v0.20.0-beta.1.0.20201105173512-3990421b69a0
|
||||||
k8s.io/klog/v2 v2.2.0
|
k8s.io/klog/v2 v2.2.0
|
||||||
k8s.io/utils v0.0.0-20200729134348-d5654de09c73
|
k8s.io/utils v0.0.0-20200729134348-d5654de09c73
|
||||||
)
|
)
|
||||||
|
4
go.sum
4
go.sum
@ -722,8 +722,8 @@ k8s.io/client-go v0.19.4/go.mod h1:ZrEy7+wj9PjH5VMBCuu/BDlvtUAku0oVFk4MmnW9mWA=
|
|||||||
k8s.io/component-base v0.19.4 h1:HobPRToQ8KJ9ubRju6PUAk9I5V1GNMJZ4PyWbiWA0uI=
|
k8s.io/component-base v0.19.4 h1:HobPRToQ8KJ9ubRju6PUAk9I5V1GNMJZ4PyWbiWA0uI=
|
||||||
k8s.io/component-base v0.19.4/go.mod h1:ZzuSLlsWhajIDEkKF73j64Gz/5o0AgON08FgRbEPI70=
|
k8s.io/component-base v0.19.4/go.mod h1:ZzuSLlsWhajIDEkKF73j64Gz/5o0AgON08FgRbEPI70=
|
||||||
k8s.io/cri-api v0.17.3/go.mod h1:X1sbHmuXhwaHs9xxYffLqJogVsnI+f6cPRcgPel7ywM=
|
k8s.io/cri-api v0.17.3/go.mod h1:X1sbHmuXhwaHs9xxYffLqJogVsnI+f6cPRcgPel7ywM=
|
||||||
k8s.io/cri-api v0.19.4 h1:Vc00x5LSSbLBgvj7UAi4kjsv276n4SGX0XlI/pWhG2E=
|
k8s.io/cri-api v0.20.0-beta.1.0.20201105173512-3990421b69a0 h1:/AO/xlTAHFP+ZLhfYMjSUzMsZe9of1fwh1TupXAKzKE=
|
||||||
k8s.io/cri-api v0.19.4/go.mod h1:UN/iU9Ua0iYdDREBXNE9vqCJ7MIh/FW3VIL0d8pw7Fw=
|
k8s.io/cri-api v0.20.0-beta.1.0.20201105173512-3990421b69a0/go.mod h1:UN/iU9Ua0iYdDREBXNE9vqCJ7MIh/FW3VIL0d8pw7Fw=
|
||||||
k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
|
k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
|
||||||
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
|
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
|
||||||
k8s.io/klog/v2 v2.2.0 h1:XRvcwJozkgZ1UQJmfMGpvRthQHOvihEhYtDfAaxMz/A=
|
k8s.io/klog/v2 v2.2.0 h1:XRvcwJozkgZ1UQJmfMGpvRthQHOvihEhYtDfAaxMz/A=
|
||||||
|
@ -306,8 +306,15 @@ func (c *criService) containerSpecOpts(config *runtime.ContainerConfig, imageCon
|
|||||||
}
|
}
|
||||||
specOpts = append(specOpts, customopts.WithAdditionalGIDs(userstr))
|
specOpts = append(specOpts, customopts.WithAdditionalGIDs(userstr))
|
||||||
|
|
||||||
|
asp := securityContext.GetApparmor()
|
||||||
|
if asp == nil {
|
||||||
|
asp, err = generateApparmorSecurityProfile(securityContext.GetApparmorProfile()) // nolint:staticcheck deprecated but we don't want to remove yet
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed to generate apparmor spec opts")
|
||||||
|
}
|
||||||
|
}
|
||||||
apparmorSpecOpts, err := generateApparmorSpecOpts(
|
apparmorSpecOpts, err := generateApparmorSpecOpts(
|
||||||
securityContext.GetApparmorProfile(),
|
asp,
|
||||||
securityContext.GetPrivileged(),
|
securityContext.GetPrivileged(),
|
||||||
c.apparmorEnabled())
|
c.apparmorEnabled())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -317,8 +324,17 @@ func (c *criService) containerSpecOpts(config *runtime.ContainerConfig, imageCon
|
|||||||
specOpts = append(specOpts, apparmorSpecOpts)
|
specOpts = append(specOpts, apparmorSpecOpts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssp := securityContext.GetSeccomp()
|
||||||
|
if ssp == nil {
|
||||||
|
ssp, err = generateSeccompSecurityProfile(
|
||||||
|
securityContext.GetSeccompProfilePath(), // nolint:staticcheck deprecated but we don't want to remove yet
|
||||||
|
c.config.UnsetSeccompProfile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed to generate seccomp spec opts")
|
||||||
|
}
|
||||||
|
}
|
||||||
seccompSpecOpts, err := c.generateSeccompSpecOpts(
|
seccompSpecOpts, err := c.generateSeccompSpecOpts(
|
||||||
securityContext.GetSeccompProfilePath(),
|
ssp,
|
||||||
securityContext.GetPrivileged(),
|
securityContext.GetPrivileged(),
|
||||||
c.seccompEnabled())
|
c.seccompEnabled())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -330,70 +346,119 @@ func (c *criService) containerSpecOpts(config *runtime.ContainerConfig, imageCon
|
|||||||
return specOpts, nil
|
return specOpts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func generateSeccompSecurityProfile(profilePath string, unsetProfilePath string) (*runtime.SecurityProfile, error) {
|
||||||
|
if profilePath != "" {
|
||||||
|
return generateSecurityProfile(profilePath)
|
||||||
|
}
|
||||||
|
if unsetProfilePath != "" {
|
||||||
|
return generateSecurityProfile(unsetProfilePath)
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
func generateApparmorSecurityProfile(profilePath string) (*runtime.SecurityProfile, error) {
|
||||||
|
if profilePath != "" {
|
||||||
|
return generateSecurityProfile(profilePath)
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateSecurityProfile(profilePath string) (*runtime.SecurityProfile, error) {
|
||||||
|
switch profilePath {
|
||||||
|
case runtimeDefault, dockerDefault, "":
|
||||||
|
return &runtime.SecurityProfile{
|
||||||
|
ProfileType: runtime.SecurityProfile_RuntimeDefault,
|
||||||
|
}, nil
|
||||||
|
case unconfinedProfile:
|
||||||
|
return &runtime.SecurityProfile{
|
||||||
|
ProfileType: runtime.SecurityProfile_Unconfined,
|
||||||
|
}, nil
|
||||||
|
default:
|
||||||
|
// Require and Trim default profile name prefix
|
||||||
|
if !strings.HasPrefix(profilePath, profileNamePrefix) {
|
||||||
|
return nil, errors.Errorf("invalid profile %q", profilePath)
|
||||||
|
}
|
||||||
|
return &runtime.SecurityProfile{
|
||||||
|
ProfileType: runtime.SecurityProfile_Localhost,
|
||||||
|
LocalhostRef: strings.TrimPrefix(profilePath, profileNamePrefix),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// generateSeccompSpecOpts generates containerd SpecOpts for seccomp.
|
// generateSeccompSpecOpts generates containerd SpecOpts for seccomp.
|
||||||
func (c *criService) generateSeccompSpecOpts(seccompProf string, privileged, seccompEnabled bool) (oci.SpecOpts, error) {
|
func (c *criService) generateSeccompSpecOpts(sp *runtime.SecurityProfile, privileged, seccompEnabled bool) (oci.SpecOpts, error) {
|
||||||
if privileged {
|
if privileged {
|
||||||
// Do not set seccomp profile when container is privileged
|
// Do not set seccomp profile when container is privileged
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
if seccompProf == "" {
|
|
||||||
seccompProf = c.config.UnsetSeccompProfile
|
|
||||||
}
|
|
||||||
// Set seccomp profile
|
|
||||||
if seccompProf == runtimeDefault || seccompProf == dockerDefault {
|
|
||||||
// use correct default profile (Eg. if not configured otherwise, the default is docker/default)
|
|
||||||
seccompProf = seccompDefaultProfile
|
|
||||||
}
|
|
||||||
if !seccompEnabled {
|
if !seccompEnabled {
|
||||||
if seccompProf != "" && seccompProf != unconfinedProfile {
|
if sp != nil {
|
||||||
|
if sp.ProfileType != runtime.SecurityProfile_Unconfined {
|
||||||
return nil, errors.New("seccomp is not supported")
|
return nil, errors.New("seccomp is not supported")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
switch seccompProf {
|
|
||||||
case "", unconfinedProfile:
|
if sp == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if sp.ProfileType != runtime.SecurityProfile_Localhost && sp.LocalhostRef != "" {
|
||||||
|
return nil, errors.New("seccomp config invalid LocalhostRef must only be set if ProfileType is Localhost")
|
||||||
|
}
|
||||||
|
switch sp.ProfileType {
|
||||||
|
case runtime.SecurityProfile_Unconfined:
|
||||||
// Do not set seccomp profile.
|
// Do not set seccomp profile.
|
||||||
return nil, nil
|
return nil, nil
|
||||||
case dockerDefault:
|
case runtime.SecurityProfile_RuntimeDefault:
|
||||||
// Note: WithDefaultProfile specOpts must be added after capabilities
|
|
||||||
return seccomp.WithDefaultProfile(), nil
|
return seccomp.WithDefaultProfile(), nil
|
||||||
|
case runtime.SecurityProfile_Localhost:
|
||||||
|
// trimming the localhost/ prefix just in case even though it should not
|
||||||
|
// be necessary with the new SecurityProfile struct
|
||||||
|
return seccomp.WithProfile(strings.TrimPrefix(sp.LocalhostRef, profileNamePrefix)), nil
|
||||||
default:
|
default:
|
||||||
// Require and Trim default profile name prefix
|
return nil, errors.New("seccomp unknown ProfileType")
|
||||||
if !strings.HasPrefix(seccompProf, profileNamePrefix) {
|
|
||||||
return nil, errors.Errorf("invalid seccomp profile %q", seccompProf)
|
|
||||||
}
|
|
||||||
return seccomp.WithProfile(strings.TrimPrefix(seccompProf, profileNamePrefix)), nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// generateApparmorSpecOpts generates containerd SpecOpts for apparmor.
|
// generateApparmorSpecOpts generates containerd SpecOpts for apparmor.
|
||||||
func generateApparmorSpecOpts(apparmorProf string, privileged, apparmorEnabled bool) (oci.SpecOpts, error) {
|
func generateApparmorSpecOpts(sp *runtime.SecurityProfile, privileged, apparmorEnabled bool) (oci.SpecOpts, error) {
|
||||||
if !apparmorEnabled {
|
if !apparmorEnabled {
|
||||||
// Should fail loudly if user try to specify apparmor profile
|
// Should fail loudly if user try to specify apparmor profile
|
||||||
// but we don't support it.
|
// but we don't support it.
|
||||||
if apparmorProf != "" && apparmorProf != unconfinedProfile {
|
if sp != nil {
|
||||||
|
if sp.ProfileType != runtime.SecurityProfile_Unconfined {
|
||||||
return nil, errors.New("apparmor is not supported")
|
return nil, errors.New("apparmor is not supported")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
switch apparmorProf {
|
|
||||||
|
if sp == nil {
|
||||||
// Based on kubernetes#51746, default apparmor profile should be applied
|
// Based on kubernetes#51746, default apparmor profile should be applied
|
||||||
// for when apparmor is not specified.
|
// for when apparmor is not specified.
|
||||||
case runtimeDefault, "":
|
sp, _ = generateSecurityProfile("")
|
||||||
|
}
|
||||||
|
|
||||||
|
if sp.ProfileType != runtime.SecurityProfile_Localhost && sp.LocalhostRef != "" {
|
||||||
|
return nil, errors.New("apparmor config invalid LocalhostRef must only be set if ProfileType is Localhost")
|
||||||
|
}
|
||||||
|
|
||||||
|
switch sp.ProfileType {
|
||||||
|
case runtime.SecurityProfile_Unconfined:
|
||||||
|
// Do not set apparmor profile.
|
||||||
|
return nil, nil
|
||||||
|
case runtime.SecurityProfile_RuntimeDefault:
|
||||||
if privileged {
|
if privileged {
|
||||||
// Do not set apparmor profile when container is privileged
|
// Do not set apparmor profile when container is privileged
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
// TODO (mikebrow): delete created apparmor default profile
|
// TODO (mikebrow): delete created apparmor default profile
|
||||||
return apparmor.WithDefaultProfile(appArmorDefaultProfileName), nil
|
return apparmor.WithDefaultProfile(appArmorDefaultProfileName), nil
|
||||||
case unconfinedProfile:
|
case runtime.SecurityProfile_Localhost:
|
||||||
return nil, nil
|
// trimming the localhost/ prefix just in case even through it should not
|
||||||
default:
|
// be necessary with the new SecurityProfile struct
|
||||||
// Require and Trim default profile name prefix
|
appArmorProfile := strings.TrimPrefix(sp.LocalhostRef, profileNamePrefix)
|
||||||
if !strings.HasPrefix(apparmorProf, profileNamePrefix) {
|
|
||||||
return nil, errors.Errorf("invalid apparmor profile %q", apparmorProf)
|
|
||||||
}
|
|
||||||
appArmorProfile := strings.TrimPrefix(apparmorProf, profileNamePrefix)
|
|
||||||
if profileExists, err := appArmorProfileExists(appArmorProfile); !profileExists {
|
if profileExists, err := appArmorProfileExists(appArmorProfile); !profileExists {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "failed to generate apparmor spec opts")
|
return nil, errors.Wrap(err, "failed to generate apparmor spec opts")
|
||||||
@ -401,6 +466,8 @@ func generateApparmorSpecOpts(apparmorProf string, privileged, apparmorEnabled b
|
|||||||
return nil, errors.Errorf("apparmor profile not found %s", appArmorProfile)
|
return nil, errors.Errorf("apparmor profile not found %s", appArmorProfile)
|
||||||
}
|
}
|
||||||
return apparmor.WithProfile(appArmorProfile), nil
|
return apparmor.WithProfile(appArmorProfile), nil
|
||||||
|
default:
|
||||||
|
return nil, errors.New("apparmor unknown ProfileType")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -787,7 +787,7 @@ func TestNoDefaultRunMount(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGenerateSeccompSpecOpts(t *testing.T) {
|
func TestGenerateSeccompSecurityProfileSpecOpts(t *testing.T) {
|
||||||
for desc, test := range map[string]struct {
|
for desc, test := range map[string]struct {
|
||||||
profile string
|
profile string
|
||||||
privileged bool
|
privileged bool
|
||||||
@ -795,6 +795,7 @@ func TestGenerateSeccompSpecOpts(t *testing.T) {
|
|||||||
specOpts oci.SpecOpts
|
specOpts oci.SpecOpts
|
||||||
expectErr bool
|
expectErr bool
|
||||||
defaultProfile string
|
defaultProfile string
|
||||||
|
sp *runtime.SecurityProfile
|
||||||
}{
|
}{
|
||||||
"should return error if seccomp is specified when seccomp is not supported": {
|
"should return error if seccomp is specified when seccomp is not supported": {
|
||||||
profile: runtimeDefault,
|
profile: runtimeDefault,
|
||||||
@ -831,10 +832,6 @@ func TestGenerateSeccompSpecOpts(t *testing.T) {
|
|||||||
profile: profileNamePrefix + "test-profile",
|
profile: profileNamePrefix + "test-profile",
|
||||||
specOpts: seccomp.WithProfile("test-profile"),
|
specOpts: seccomp.WithProfile("test-profile"),
|
||||||
},
|
},
|
||||||
"should return error if specified profile is invalid": {
|
|
||||||
profile: "test-profile",
|
|
||||||
expectErr: true,
|
|
||||||
},
|
|
||||||
"should use default profile when seccomp is empty": {
|
"should use default profile when seccomp is empty": {
|
||||||
defaultProfile: profileNamePrefix + "test-profile",
|
defaultProfile: profileNamePrefix + "test-profile",
|
||||||
specOpts: seccomp.WithProfile("test-profile"),
|
specOpts: seccomp.WithProfile("test-profile"),
|
||||||
@ -843,11 +840,80 @@ func TestGenerateSeccompSpecOpts(t *testing.T) {
|
|||||||
defaultProfile: runtimeDefault,
|
defaultProfile: runtimeDefault,
|
||||||
specOpts: seccomp.WithDefaultProfile(),
|
specOpts: seccomp.WithDefaultProfile(),
|
||||||
},
|
},
|
||||||
|
//-----------------------------------------------
|
||||||
|
// now buckets for the SecurityProfile variants
|
||||||
|
//-----------------------------------------------
|
||||||
|
"sp should return error if seccomp is specified when seccomp is not supported": {
|
||||||
|
disable: true,
|
||||||
|
expectErr: true,
|
||||||
|
sp: &runtime.SecurityProfile{
|
||||||
|
ProfileType: runtime.SecurityProfile_RuntimeDefault,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"sp should not return error if seccomp is unconfined when seccomp is not supported": {
|
||||||
|
disable: true,
|
||||||
|
sp: &runtime.SecurityProfile{
|
||||||
|
ProfileType: runtime.SecurityProfile_Unconfined,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"sp should not set seccomp when privileged is true": {
|
||||||
|
privileged: true,
|
||||||
|
sp: &runtime.SecurityProfile{
|
||||||
|
ProfileType: runtime.SecurityProfile_RuntimeDefault,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"sp should not set seccomp when seccomp is unconfined": {
|
||||||
|
sp: &runtime.SecurityProfile{
|
||||||
|
ProfileType: runtime.SecurityProfile_Unconfined,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"sp should not set seccomp when seccomp is not specified": {},
|
||||||
|
"sp should set default seccomp when seccomp is runtime/default": {
|
||||||
|
specOpts: seccomp.WithDefaultProfile(),
|
||||||
|
sp: &runtime.SecurityProfile{
|
||||||
|
ProfileType: runtime.SecurityProfile_RuntimeDefault,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"sp should set specified profile when local profile is specified": {
|
||||||
|
specOpts: seccomp.WithProfile("test-profile"),
|
||||||
|
sp: &runtime.SecurityProfile{
|
||||||
|
ProfileType: runtime.SecurityProfile_Localhost,
|
||||||
|
LocalhostRef: profileNamePrefix + "test-profile",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"sp should set specified profile when local profile is specified even without prefix": {
|
||||||
|
specOpts: seccomp.WithProfile("test-profile"),
|
||||||
|
sp: &runtime.SecurityProfile{
|
||||||
|
ProfileType: runtime.SecurityProfile_Localhost,
|
||||||
|
LocalhostRef: "test-profile",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"sp should return error if specified profile is invalid": {
|
||||||
|
expectErr: true,
|
||||||
|
sp: &runtime.SecurityProfile{
|
||||||
|
ProfileType: runtime.SecurityProfile_RuntimeDefault,
|
||||||
|
LocalhostRef: "test-profile",
|
||||||
|
},
|
||||||
|
},
|
||||||
} {
|
} {
|
||||||
t.Run(fmt.Sprintf("TestCase %q", desc), func(t *testing.T) {
|
t.Run(fmt.Sprintf("TestCase %q", desc), func(t *testing.T) {
|
||||||
cri := &criService{}
|
cri := &criService{}
|
||||||
cri.config.UnsetSeccompProfile = test.defaultProfile
|
cri.config.UnsetSeccompProfile = test.defaultProfile
|
||||||
specOpts, err := cri.generateSeccompSpecOpts(test.profile, test.privileged, !test.disable)
|
ssp := test.sp
|
||||||
|
csp, err := generateSeccompSecurityProfile(
|
||||||
|
test.profile,
|
||||||
|
test.defaultProfile)
|
||||||
|
if err != nil {
|
||||||
|
if test.expectErr {
|
||||||
|
assert.Error(t, err)
|
||||||
|
} else {
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ssp == nil {
|
||||||
|
ssp = csp
|
||||||
|
}
|
||||||
|
specOpts, err := cri.generateSeccompSpecOpts(ssp, test.privileged, !test.disable)
|
||||||
assert.Equal(t,
|
assert.Equal(t,
|
||||||
reflect.ValueOf(test.specOpts).Pointer(),
|
reflect.ValueOf(test.specOpts).Pointer(),
|
||||||
reflect.ValueOf(specOpts).Pointer())
|
reflect.ValueOf(specOpts).Pointer())
|
||||||
@ -856,6 +922,7 @@ func TestGenerateSeccompSpecOpts(t *testing.T) {
|
|||||||
} else {
|
} else {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -867,6 +934,7 @@ func TestGenerateApparmorSpecOpts(t *testing.T) {
|
|||||||
disable bool
|
disable bool
|
||||||
specOpts oci.SpecOpts
|
specOpts oci.SpecOpts
|
||||||
expectErr bool
|
expectErr bool
|
||||||
|
sp *runtime.SecurityProfile
|
||||||
}{
|
}{
|
||||||
"should return error if apparmor is specified when apparmor is not supported": {
|
"should return error if apparmor is specified when apparmor is not supported": {
|
||||||
profile: runtimeDefault,
|
profile: runtimeDefault,
|
||||||
@ -918,9 +986,83 @@ func TestGenerateApparmorSpecOpts(t *testing.T) {
|
|||||||
profile: "test-profile",
|
profile: "test-profile",
|
||||||
expectErr: true,
|
expectErr: true,
|
||||||
},
|
},
|
||||||
|
//--------------------------------------
|
||||||
|
// buckets for SecurityProfile struct
|
||||||
|
//--------------------------------------
|
||||||
|
"sp should return error if apparmor is specified when apparmor is not supported": {
|
||||||
|
disable: true,
|
||||||
|
expectErr: true,
|
||||||
|
sp: &runtime.SecurityProfile{
|
||||||
|
ProfileType: runtime.SecurityProfile_RuntimeDefault,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"sp should not return error if apparmor is unconfined when apparmor is not supported": {
|
||||||
|
disable: true,
|
||||||
|
sp: &runtime.SecurityProfile{
|
||||||
|
ProfileType: runtime.SecurityProfile_Unconfined,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"sp should not apparmor when apparmor is unconfined": {
|
||||||
|
sp: &runtime.SecurityProfile{
|
||||||
|
ProfileType: runtime.SecurityProfile_Unconfined,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"sp should not apparmor when apparmor is unconfined and privileged is true": {
|
||||||
|
privileged: true,
|
||||||
|
sp: &runtime.SecurityProfile{
|
||||||
|
ProfileType: runtime.SecurityProfile_Unconfined,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"sp should set default apparmor when apparmor is runtime/default": {
|
||||||
|
specOpts: apparmor.WithDefaultProfile(appArmorDefaultProfileName),
|
||||||
|
sp: &runtime.SecurityProfile{
|
||||||
|
ProfileType: runtime.SecurityProfile_RuntimeDefault,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"sp should not apparmor when apparmor is default and privileged is true": {
|
||||||
|
privileged: true,
|
||||||
|
sp: &runtime.SecurityProfile{
|
||||||
|
ProfileType: runtime.SecurityProfile_RuntimeDefault,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"sp should return error when undefined local profile is specified": {
|
||||||
|
expectErr: true,
|
||||||
|
sp: &runtime.SecurityProfile{
|
||||||
|
ProfileType: runtime.SecurityProfile_Localhost,
|
||||||
|
LocalhostRef: profileNamePrefix + "test-profile",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"sp should return error when undefined local profile is specified even without prefix": {
|
||||||
|
profile: profileNamePrefix + "test-profile",
|
||||||
|
expectErr: true,
|
||||||
|
sp: &runtime.SecurityProfile{
|
||||||
|
ProfileType: runtime.SecurityProfile_Localhost,
|
||||||
|
LocalhostRef: "test-profile",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"sp should return error when undefined local profile is specified and privileged is true": {
|
||||||
|
privileged: true,
|
||||||
|
expectErr: true,
|
||||||
|
sp: &runtime.SecurityProfile{
|
||||||
|
ProfileType: runtime.SecurityProfile_Localhost,
|
||||||
|
LocalhostRef: profileNamePrefix + "test-profile",
|
||||||
|
},
|
||||||
|
},
|
||||||
} {
|
} {
|
||||||
t.Logf("TestCase %q", desc)
|
t.Logf("TestCase %q", desc)
|
||||||
specOpts, err := generateApparmorSpecOpts(test.profile, test.privileged, !test.disable)
|
asp := test.sp
|
||||||
|
csp, err := generateApparmorSecurityProfile(test.profile)
|
||||||
|
if err != nil {
|
||||||
|
if test.expectErr {
|
||||||
|
assert.Error(t, err)
|
||||||
|
} else {
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if asp == nil {
|
||||||
|
asp = csp
|
||||||
|
}
|
||||||
|
specOpts, err := generateApparmorSpecOpts(asp, test.privileged, !test.disable)
|
||||||
assert.Equal(t,
|
assert.Equal(t,
|
||||||
reflect.ValueOf(test.specOpts).Pointer(),
|
reflect.ValueOf(test.specOpts).Pointer(),
|
||||||
reflect.ValueOf(specOpts).Pointer())
|
reflect.ValueOf(specOpts).Pointer())
|
||||||
@ -931,6 +1073,7 @@ func TestGenerateApparmorSpecOpts(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestMaskedAndReadonlyPaths(t *testing.T) {
|
func TestMaskedAndReadonlyPaths(t *testing.T) {
|
||||||
testID := "test-id"
|
testID := "test-id"
|
||||||
|
@ -163,9 +163,19 @@ func (c *criService) sandboxContainerSpecOpts(config *runtime.PodSandboxConfig,
|
|||||||
var (
|
var (
|
||||||
securityContext = config.GetLinux().GetSecurityContext()
|
securityContext = config.GetLinux().GetSecurityContext()
|
||||||
specOpts []oci.SpecOpts
|
specOpts []oci.SpecOpts
|
||||||
|
err error
|
||||||
)
|
)
|
||||||
|
ssp := securityContext.GetSeccomp()
|
||||||
|
if ssp == nil {
|
||||||
|
ssp, err = generateSeccompSecurityProfile(
|
||||||
|
securityContext.GetSeccompProfilePath(), // nolint:staticcheck deprecated but we don't want to remove yet
|
||||||
|
c.config.UnsetSeccompProfile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed to generate seccomp spec opts")
|
||||||
|
}
|
||||||
|
}
|
||||||
seccompSpecOpts, err := c.generateSeccompSpecOpts(
|
seccompSpecOpts, err := c.generateSeccompSpecOpts(
|
||||||
securityContext.GetSeccompProfilePath(),
|
ssp,
|
||||||
securityContext.GetPrivileged(),
|
securityContext.GetPrivileged(),
|
||||||
c.seccompEnabled())
|
c.seccompEnabled())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
1438
vendor/k8s.io/cri-api/pkg/apis/runtime/v1alpha2/api.pb.go
generated
vendored
1438
vendor/k8s.io/cri-api/pkg/apis/runtime/v1alpha2/api.pb.go
generated
vendored
File diff suppressed because it is too large
Load Diff
62
vendor/k8s.io/cri-api/pkg/apis/runtime/v1alpha2/api.proto
generated
vendored
62
vendor/k8s.io/cri-api/pkg/apis/runtime/v1alpha2/api.proto
generated
vendored
@ -15,7 +15,7 @@ limitations under the License.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// To regenerate api.pb.go run hack/update-generated-runtime.sh
|
// To regenerate api.pb.go run hack/update-generated-runtime.sh
|
||||||
syntax = 'proto3';
|
syntax = "proto3";
|
||||||
|
|
||||||
package runtime.v1alpha2;
|
package runtime.v1alpha2;
|
||||||
option go_package = "v1alpha2";
|
option go_package = "v1alpha2";
|
||||||
@ -279,13 +279,37 @@ message LinuxSandboxSecurityContext {
|
|||||||
// This allows a sandbox to take additional security precautions if no
|
// This allows a sandbox to take additional security precautions if no
|
||||||
// privileged containers are expected to be run.
|
// privileged containers are expected to be run.
|
||||||
bool privileged = 6;
|
bool privileged = 6;
|
||||||
|
// Seccomp profile for the sandbox.
|
||||||
|
SecurityProfile seccomp = 9;
|
||||||
|
// AppArmor profile for the sandbox.
|
||||||
|
SecurityProfile apparmor = 10;
|
||||||
// Seccomp profile for the sandbox, candidate values are:
|
// Seccomp profile for the sandbox, candidate values are:
|
||||||
// * runtime/default: the default profile for the container runtime
|
// * runtime/default: the default profile for the container runtime
|
||||||
// * unconfined: unconfined profile, ie, no seccomp sandboxing
|
// * unconfined: unconfined profile, ie, no seccomp sandboxing
|
||||||
// * localhost/<full-path-to-profile>: the profile installed on the node.
|
// * localhost/<full-path-to-profile>: the profile installed on the node.
|
||||||
// <full-path-to-profile> is the full path of the profile.
|
// <full-path-to-profile> is the full path of the profile.
|
||||||
// Default: "", which is identical with unconfined.
|
// Default: "", which is identical with unconfined.
|
||||||
string seccomp_profile_path = 7;
|
string seccomp_profile_path = 7 [deprecated=true];
|
||||||
|
}
|
||||||
|
|
||||||
|
// A security profile which can be used for sandboxes and containers.
|
||||||
|
message SecurityProfile {
|
||||||
|
// Available profile types.
|
||||||
|
enum ProfileType {
|
||||||
|
// The container runtime default profile should be used.
|
||||||
|
RuntimeDefault = 0;
|
||||||
|
// Disable the feature for the sandbox or the container.
|
||||||
|
Unconfined = 1;
|
||||||
|
// A pre-defined profile on the node should be used.
|
||||||
|
Localhost = 2;
|
||||||
|
}
|
||||||
|
// Indicator which `ProfileType` should be applied.
|
||||||
|
ProfileType profile_type = 1;
|
||||||
|
// Indicates that a pre-defined profile on the node should be used.
|
||||||
|
// Must only be set if `ProfileType` is `Localhost`.
|
||||||
|
// For seccomp, it must be an absolute path to the seccomp profile.
|
||||||
|
// For AppArmor, this field is the AppArmor `<profile name>/`
|
||||||
|
string localhost_ref = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// LinuxPodSandboxConfig holds platform-specific configurations for Linux
|
// LinuxPodSandboxConfig holds platform-specific configurations for Linux
|
||||||
@ -604,7 +628,7 @@ message LinuxContainerSecurityContext {
|
|||||||
// 1. All capabilities are added.
|
// 1. All capabilities are added.
|
||||||
// 2. Sensitive paths, such as kernel module paths within sysfs, are not masked.
|
// 2. Sensitive paths, such as kernel module paths within sysfs, are not masked.
|
||||||
// 3. Any sysfs and procfs mounts are mounted RW.
|
// 3. Any sysfs and procfs mounts are mounted RW.
|
||||||
// 4. Apparmor confinement is not applied.
|
// 4. AppArmor confinement is not applied.
|
||||||
// 5. Seccomp restrictions are not applied.
|
// 5. Seccomp restrictions are not applied.
|
||||||
// 6. The device cgroup does not restrict access to any devices.
|
// 6. The device cgroup does not restrict access to any devices.
|
||||||
// 7. All devices from the host's /dev are available within the container.
|
// 7. All devices from the host's /dev are available within the container.
|
||||||
@ -631,20 +655,6 @@ message LinuxContainerSecurityContext {
|
|||||||
// List of groups applied to the first process run in the container, in
|
// List of groups applied to the first process run in the container, in
|
||||||
// addition to the container's primary GID.
|
// addition to the container's primary GID.
|
||||||
repeated int64 supplemental_groups = 8;
|
repeated int64 supplemental_groups = 8;
|
||||||
// AppArmor profile for the container, candidate values are:
|
|
||||||
// * runtime/default: equivalent to not specifying a profile.
|
|
||||||
// * unconfined: no profiles are loaded
|
|
||||||
// * localhost/<profile_name>: profile loaded on the node
|
|
||||||
// (localhost) by name. The possible profile names are detailed at
|
|
||||||
// http://wiki.apparmor.net/index.php/AppArmor_Core_Policy_Reference
|
|
||||||
string apparmor_profile = 9;
|
|
||||||
// Seccomp profile for the container, candidate values are:
|
|
||||||
// * runtime/default: the default profile for the container runtime
|
|
||||||
// * unconfined: unconfined profile, ie, no seccomp sandboxing
|
|
||||||
// * localhost/<full-path-to-profile>: the profile installed on the node.
|
|
||||||
// <full-path-to-profile> is the full path of the profile.
|
|
||||||
// Default: "", which is identical with unconfined.
|
|
||||||
string seccomp_profile_path = 10;
|
|
||||||
// no_new_privs defines if the flag for no_new_privs should be set on the
|
// no_new_privs defines if the flag for no_new_privs should be set on the
|
||||||
// container.
|
// container.
|
||||||
bool no_new_privs = 11;
|
bool no_new_privs = 11;
|
||||||
@ -654,6 +664,24 @@ message LinuxContainerSecurityContext {
|
|||||||
// readonly_paths is a slice of paths that should be set as readonly by the
|
// readonly_paths is a slice of paths that should be set as readonly by the
|
||||||
// container runtime, this can be passed directly to the OCI spec.
|
// container runtime, this can be passed directly to the OCI spec.
|
||||||
repeated string readonly_paths = 14;
|
repeated string readonly_paths = 14;
|
||||||
|
// Seccomp profile for the container.
|
||||||
|
SecurityProfile seccomp = 15;
|
||||||
|
// AppArmor profile for the container.
|
||||||
|
SecurityProfile apparmor = 16;
|
||||||
|
// AppArmor profile for the container, candidate values are:
|
||||||
|
// * runtime/default: equivalent to not specifying a profile.
|
||||||
|
// * unconfined: no profiles are loaded
|
||||||
|
// * localhost/<profile_name>: profile loaded on the node
|
||||||
|
// (localhost) by name. The possible profile names are detailed at
|
||||||
|
// https://gitlab.com/apparmor/apparmor/-/wikis/AppArmor_Core_Policy_Reference
|
||||||
|
string apparmor_profile = 9 [deprecated=true];
|
||||||
|
// Seccomp profile for the container, candidate values are:
|
||||||
|
// * runtime/default: the default profile for the container runtime
|
||||||
|
// * unconfined: unconfined profile, ie, no seccomp sandboxing
|
||||||
|
// * localhost/<full-path-to-profile>: the profile installed on the node.
|
||||||
|
// <full-path-to-profile> is the full path of the profile.
|
||||||
|
// Default: "", which is identical with unconfined.
|
||||||
|
string seccomp_profile_path = 10 [deprecated=true];
|
||||||
}
|
}
|
||||||
|
|
||||||
// LinuxContainerConfig contains platform-specific configuration for
|
// LinuxContainerConfig contains platform-specific configuration for
|
||||||
|
2
vendor/modules.txt
vendored
2
vendor/modules.txt
vendored
@ -512,7 +512,7 @@ k8s.io/client-go/util/workqueue
|
|||||||
# k8s.io/component-base v0.19.4
|
# k8s.io/component-base v0.19.4
|
||||||
## explicit
|
## explicit
|
||||||
k8s.io/component-base/logs/logreduction
|
k8s.io/component-base/logs/logreduction
|
||||||
# k8s.io/cri-api v0.19.4
|
# k8s.io/cri-api v0.20.0-beta.1.0.20201105173512-3990421b69a0
|
||||||
## explicit
|
## explicit
|
||||||
k8s.io/cri-api/pkg/apis
|
k8s.io/cri-api/pkg/apis
|
||||||
k8s.io/cri-api/pkg/apis/runtime/v1alpha2
|
k8s.io/cri-api/pkg/apis/runtime/v1alpha2
|
||||||
|
Loading…
Reference in New Issue
Block a user