diff --git a/changelogs/unreleased/2792-doughepi b/changelogs/unreleased/2792-doughepi new file mode 100644 index 000000000..0cb8599de --- /dev/null +++ b/changelogs/unreleased/2792-doughepi @@ -0,0 +1 @@ +Add the ability to set the allowPrivilegeEscalation flag in the securityContext for the Restic restore helper. \ No newline at end of file diff --git a/pkg/restore/restic_restore_action.go b/pkg/restore/restic_restore_action.go index 7c315703c..f41022632 100644 --- a/pkg/restore/restic_restore_action.go +++ b/pkg/restore/restic_restore_action.go @@ -130,9 +130,9 @@ func (a *ResticRestoreAction) Execute(input *velero.RestoreItemActionExecuteInpu ) } - runAsRoot, runAsGroup := getSecurityContext(log, config) + runAsRoot, runAsGroup, allowPrivilegeEscalation := getSecurityContext(log, config) - securityContext, err := kube.ParseSecurityContext(runAsRoot, runAsGroup) + securityContext, err := kube.ParseSecurityContext(runAsRoot, runAsGroup, allowPrivilegeEscalation) if err != nil { log.Errorf("Using default resource values, couldn't parse resource requirements: %s.", err) } @@ -219,14 +219,14 @@ func getResourceLimits(log logrus.FieldLogger, config *corev1.ConfigMap) (string return config.Data["cpuLimit"], config.Data["memLimit"] } -// getSecurityContext extracts securityContext runAsUser and runAsGroup from a ConfigMap. -func getSecurityContext(log logrus.FieldLogger, config *corev1.ConfigMap) (string, string) { +// getSecurityContext extracts securityContext runAsUser, runAsGroup, and allowPrivilegeEscalation from a ConfigMap. +func getSecurityContext(log logrus.FieldLogger, config *corev1.ConfigMap) (string, string, string) { if config == nil { log.Debug("No config found for plugin") - return "", "" + return "", "", "" } - return config.Data["secCtxRunAsUser"], config.Data["secCtxRunAsGroup"] + return config.Data["secCtxRunAsUser"], config.Data["secCtxRunAsGroup"], config.Data["secCtxAllowPrivilegeEscalation"] } // TODO eventually this can move to pkg/plugin/framework since it'll be used across multiple diff --git a/pkg/restore/restic_restore_action_test.go b/pkg/restore/restic_restore_action_test.go index 053fe4bc5..a079dcbaf 100644 --- a/pkg/restore/restic_restore_action_test.go +++ b/pkg/restore/restic_restore_action_test.go @@ -111,7 +111,7 @@ func TestResticRestoreActionExecute(t *testing.T) { defaultCPURequestLimit, defaultMemRequestLimit, // limits ) - securityContext, _ := kube.ParseSecurityContext("", "") + securityContext, _ := kube.ParseSecurityContext("", "", "") var ( restoreName = "my-restore" diff --git a/pkg/util/kube/security_context.go b/pkg/util/kube/security_context.go index d1e34deac..2011515ec 100644 --- a/pkg/util/kube/security_context.go +++ b/pkg/util/kube/security_context.go @@ -23,7 +23,7 @@ import ( corev1 "k8s.io/api/core/v1" ) -func ParseSecurityContext(runAsUser string, runAsGroup string) (corev1.SecurityContext, error) { +func ParseSecurityContext(runAsUser string, runAsGroup string, allowPrivilegeEscalation string) (corev1.SecurityContext, error) { securityContext := corev1.SecurityContext{} if runAsUser != "" { @@ -44,5 +44,14 @@ func ParseSecurityContext(runAsUser string, runAsGroup string) (corev1.SecurityC securityContext.RunAsGroup = &parsedRunAsGroup } + if allowPrivilegeEscalation != "" { + parsedAllowPrivilegeEscalation, err := strconv.ParseBool(allowPrivilegeEscalation) + if err != nil { + return securityContext, errors.WithStack(errors.Errorf(`Security context allowPrivilegeEscalation "%s" is not a boolean`, allowPrivilegeEscalation)) + } + + securityContext.AllowPrivilegeEscalation = &parsedAllowPrivilegeEscalation + } + return securityContext, nil } diff --git a/pkg/util/kube/security_context_test.go b/pkg/util/kube/security_context_test.go index ebdc8c956..2e20974bc 100644 --- a/pkg/util/kube/security_context_test.go +++ b/pkg/util/kube/security_context_test.go @@ -21,12 +21,15 @@ import ( "github.com/stretchr/testify/assert" corev1 "k8s.io/api/core/v1" + + "github.com/vmware-tanzu/velero/pkg/util/boolptr" ) func TestParseSecurityContext(t *testing.T) { type args struct { - runAsUser string - runAsGroup string + runAsUser string + runAsGroup string + allowPrivilegeEscalation string } tests := []struct { name string @@ -34,23 +37,33 @@ func TestParseSecurityContext(t *testing.T) { wantErr bool expected *corev1.SecurityContext }{ - {"valid security context", args{"1001", "999"}, false, &corev1.SecurityContext{ - RunAsUser: pointInt64(1001), - RunAsGroup: pointInt64(999), + {"valid security context", args{"1001", "999", "true"}, false, &corev1.SecurityContext{ + RunAsUser: pointInt64(1001), + RunAsGroup: pointInt64(999), + AllowPrivilegeEscalation: boolptr.True(), }}, - {"security context without runAsGroup", args{"1001", ""}, false, &corev1.SecurityContext{ + { + "another valid security context", + args{"1001", "999", "false"}, false, &corev1.SecurityContext{ + RunAsUser: pointInt64(1001), + RunAsGroup: pointInt64(999), + AllowPrivilegeEscalation: boolptr.False(), + }, + }, + {"security context without runAsGroup", args{"1001", "", ""}, false, &corev1.SecurityContext{ RunAsUser: pointInt64(1001), }}, - {"security context without runAsUser", args{"", "999"}, false, &corev1.SecurityContext{ + {"security context without runAsUser", args{"", "999", ""}, false, &corev1.SecurityContext{ RunAsGroup: pointInt64(999), }}, - {"empty context without runAsUser", args{"", ""}, false, &corev1.SecurityContext{}}, - {"invalid security context runAsUser", args{"not a number", ""}, true, nil}, - {"invalid security context runAsGroup", args{"", "not a number"}, true, nil}, + {"empty context without runAsUser", args{"", "", ""}, false, &corev1.SecurityContext{}}, + {"invalid security context runAsUser", args{"not a number", "", ""}, true, nil}, + {"invalid security context runAsGroup", args{"", "not a number", ""}, true, nil}, + {"invalid security context allowPrivilegeEscalation", args{"", "", "not a bool"}, true, nil}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := ParseSecurityContext(tt.args.runAsUser, tt.args.runAsGroup) + got, err := ParseSecurityContext(tt.args.runAsUser, tt.args.runAsGroup, tt.args.allowPrivilegeEscalation) if tt.wantErr { assert.Error(t, err) return