adding code to support seccomp apparmor securityprofile
Signed-off-by: Mike Brown <brownwm@us.ibm.com>
This commit is contained in:
parent
f1295043eb
commit
b4727eafbe
@ -307,7 +307,8 @@ func (c *criService) containerSpecOpts(config *runtime.ContainerConfig, imageCon
|
|||||||
specOpts = append(specOpts, customopts.WithAdditionalGIDs(userstr))
|
specOpts = append(specOpts, customopts.WithAdditionalGIDs(userstr))
|
||||||
|
|
||||||
apparmorSpecOpts, err := generateApparmorSpecOpts(
|
apparmorSpecOpts, err := generateApparmorSpecOpts(
|
||||||
securityContext.GetApparmorProfile(),
|
securityContext.GetApparmor(),
|
||||||
|
securityContext.GetApparmorProfile(), // nolint:staticcheck deprecated but we don't want to remove yet
|
||||||
securityContext.GetPrivileged(),
|
securityContext.GetPrivileged(),
|
||||||
c.apparmorEnabled())
|
c.apparmorEnabled())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -318,7 +319,8 @@ func (c *criService) containerSpecOpts(config *runtime.ContainerConfig, imageCon
|
|||||||
}
|
}
|
||||||
|
|
||||||
seccompSpecOpts, err := c.generateSeccompSpecOpts(
|
seccompSpecOpts, err := c.generateSeccompSpecOpts(
|
||||||
securityContext.GetSeccompProfilePath(),
|
securityContext.GetSeccomp(),
|
||||||
|
securityContext.GetSeccompProfilePath(), // nolint:staticcheck deprecated but we don't want to remove yet
|
||||||
securityContext.GetPrivileged(),
|
securityContext.GetPrivileged(),
|
||||||
c.seccompEnabled())
|
c.seccompEnabled())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -331,12 +333,12 @@ func (c *criService) containerSpecOpts(config *runtime.ContainerConfig, imageCon
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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, seccompProf string, 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 == "" {
|
if seccompProf == "" && sp == nil {
|
||||||
seccompProf = c.config.UnsetSeccompProfile
|
seccompProf = c.config.UnsetSeccompProfile
|
||||||
}
|
}
|
||||||
// Set seccomp profile
|
// Set seccomp profile
|
||||||
@ -348,8 +350,33 @@ func (c *criService) generateSeccompSpecOpts(seccompProf string, privileged, sec
|
|||||||
if seccompProf != "" && seccompProf != unconfinedProfile {
|
if seccompProf != "" && seccompProf != unconfinedProfile {
|
||||||
return nil, errors.New("seccomp is not supported")
|
return nil, errors.New("seccomp is not supported")
|
||||||
}
|
}
|
||||||
|
if sp != nil {
|
||||||
|
if sp.ProfileType != runtime.SecurityProfile_Unconfined {
|
||||||
|
return nil, errors.New("seccomp is not supported")
|
||||||
|
}
|
||||||
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if sp != 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.
|
||||||
|
return nil, nil
|
||||||
|
case runtime.SecurityProfile_RuntimeDefault:
|
||||||
|
return seccomp.WithDefaultProfile(), nil
|
||||||
|
case runtime.SecurityProfile_Localhost:
|
||||||
|
// trimming the localhost/ prefix just in case even through it should not
|
||||||
|
// be necessary with the new SecurityProfile struct
|
||||||
|
return seccomp.WithProfile(strings.TrimPrefix(sp.LocalhostRef, profileNamePrefix)), nil
|
||||||
|
default:
|
||||||
|
return nil, errors.New("seccomp unknown ProfileType")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch seccompProf {
|
switch seccompProf {
|
||||||
case "", unconfinedProfile:
|
case "", unconfinedProfile:
|
||||||
// Do not set seccomp profile.
|
// Do not set seccomp profile.
|
||||||
@ -367,15 +394,52 @@ func (c *criService) generateSeccompSpecOpts(seccompProf string, privileged, sec
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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, apparmorProf string, 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 apparmorProf != "" && apparmorProf != unconfinedProfile {
|
||||||
return nil, errors.New("apparmor is not supported")
|
return nil, errors.New("apparmor is not supported")
|
||||||
}
|
}
|
||||||
|
if sp != nil {
|
||||||
|
if sp.ProfileType != runtime.SecurityProfile_Unconfined {
|
||||||
|
return nil, errors.New("apparmor is not supported")
|
||||||
|
}
|
||||||
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if sp != nil {
|
||||||
|
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 {
|
||||||
|
// Do not set apparmor profile when container is privileged
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return apparmor.WithDefaultProfile(appArmorDefaultProfileName), nil
|
||||||
|
case runtime.SecurityProfile_Localhost:
|
||||||
|
// trimming the localhost/ prefix just in case even through it should not
|
||||||
|
// be necessary with the new SecurityProfile struct
|
||||||
|
appArmorProfile := strings.TrimPrefix(sp.LocalhostRef, profileNamePrefix)
|
||||||
|
if profileExists, err := appArmorProfileExists(appArmorProfile); !profileExists {
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed to generate apparmor spec opts")
|
||||||
|
}
|
||||||
|
return nil, errors.Errorf("apparmor profile not found %s", appArmorProfile)
|
||||||
|
}
|
||||||
|
return apparmor.WithProfile(appArmorProfile), nil
|
||||||
|
default:
|
||||||
|
return nil, errors.New("apparmor unknown ProfileType")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch apparmorProf {
|
switch apparmorProf {
|
||||||
// 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.
|
||||||
|
@ -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,
|
||||||
@ -843,11 +844,66 @@ 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)
|
specOpts, err := cri.generateSeccompSpecOpts(test.sp, test.profile, 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())
|
||||||
@ -867,6 +923,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 +975,71 @@ 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)
|
specOpts, err := generateApparmorSpecOpts(test.sp, test.profile, 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())
|
||||||
|
@ -165,7 +165,8 @@ func (c *criService) sandboxContainerSpecOpts(config *runtime.PodSandboxConfig,
|
|||||||
specOpts []oci.SpecOpts
|
specOpts []oci.SpecOpts
|
||||||
)
|
)
|
||||||
seccompSpecOpts, err := c.generateSeccompSpecOpts(
|
seccompSpecOpts, err := c.generateSeccompSpecOpts(
|
||||||
securityContext.GetSeccompProfilePath(),
|
securityContext.GetSeccomp(),
|
||||||
|
securityContext.GetSeccompProfilePath(), // nolint:staticcheck deprecated but we don't want to remove yet
|
||||||
securityContext.GetPrivileged(),
|
securityContext.GetPrivileged(),
|
||||||
c.seccompEnabled())
|
c.seccompEnabled())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Loading…
Reference in New Issue
Block a user