Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: runtime run as no-root user #6474

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,6 @@ func updatePodAndInstance(dbclient *instanceinfo.Client, podlist *corev1.PodList
}
}
} else {
logrus.Infof("get [currentContainerID] from mainContainer")
currentTerminatedContainer := mainContainer.State.Terminated
if currentTerminatedContainer != nil {
if len(strings.Split(mainContainer.ContainerID, "://")) == 2 {
Expand Down
33 changes: 33 additions & 0 deletions internal/tools/orchestrator/scheduler/executor/plugins/k8s/k8s.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
"github.com/erda-project/erda/pkg/k8sclient"
k8sclientconfig "github.com/erda-project/erda/pkg/k8sclient/config"
"github.com/erda-project/erda/pkg/k8sclient/scheme"
"github.com/erda-project/erda/pkg/parser/diceyml"
"github.com/erda-project/erda/pkg/schedule/schedulepolicy/cpupolicy"
"github.com/erda-project/erda/pkg/strutil"
)
Expand Down Expand Up @@ -789,6 +790,13 @@
}
}
var err error

if err = k.runAsDefaultUser(service); err != nil {
return err
}

Check warning on line 796 in internal/tools/orchestrator/scheduler/executor/plugins/k8s/k8s.go

View check run for this annotation

Codecov / codecov/patch

internal/tools/orchestrator/scheduler/executor/plugins/k8s/k8s.go#L793-L796

Added lines #L793 - L796 were not covered by tests

logrus.Infof("after %v", service.K8SSnippet.Container.SecurityContext)

Check warning on line 799 in internal/tools/orchestrator/scheduler/executor/plugins/k8s/k8s.go

View check run for this annotation

Codecov / codecov/patch

internal/tools/orchestrator/scheduler/executor/plugins/k8s/k8s.go#L798-L799

Added lines #L798 - L799 were not covered by tests
switch service.WorkLoad {
case types.ServicePerNode:
err = k.createDaemonSet(ctx, service, sg)
Expand Down Expand Up @@ -903,6 +911,12 @@
}

for _, svc := range sg.Services {
svc := svc

if err := k.runAsDefaultUser(&svc); err != nil {
return err
}

Check warning on line 918 in internal/tools/orchestrator/scheduler/executor/plugins/k8s/k8s.go

View check run for this annotation

Codecov / codecov/patch

internal/tools/orchestrator/scheduler/executor/plugins/k8s/k8s.go#L914-L918

Added lines #L914 - L918 were not covered by tests

svc.Namespace = ns
runtimeServiceName := util.GetDeployName(&svc)
// Existing in the old service collection, do the put operation
Expand Down Expand Up @@ -2058,3 +2072,22 @@

return true
}

// run as default user
func (k *Kubernetes) runAsDefaultUser(service *apistructs.Service) error {
snippet := diceyml.K8SSnippet{
Container: &diceyml.ContainerSnippet{
SecurityContext: &apiv1.SecurityContext{
RunAsUser: &types.DefaultContainerUserId,
RunAsGroup: &types.DefaultContainerGroupId,
},
},
}

if service.K8SSnippet == nil {
service.K8SSnippet = &snippet
return nil
}

Check warning on line 2090 in internal/tools/orchestrator/scheduler/executor/plugins/k8s/k8s.go

View check run for this annotation

Codecov / codecov/patch

internal/tools/orchestrator/scheduler/executor/plugins/k8s/k8s.go#L2077-L2090

Added lines #L2077 - L2090 were not covered by tests

return util.MergeStruct(service.K8SSnippet, &snippet)

Check warning on line 2092 in internal/tools/orchestrator/scheduler/executor/plugins/k8s/k8s.go

View check run for this annotation

Codecov / codecov/patch

internal/tools/orchestrator/scheduler/executor/plugins/k8s/k8s.go#L2092

Added line #L2092 was not covered by tests
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ const (
DiceWorkSpace = "DICE_WORKSPACE"
)

var (
DefaultContainerUserId int64 = 1000 // `dice` user
DefaultContainerGroupId int64 = 1000 // `dice` group
)

var EnvReg = regexp.MustCompile(`\$\{([^}]+?)\}`)

type StatefulsetInfo struct {
Expand Down
95 changes: 95 additions & 0 deletions internal/tools/orchestrator/scheduler/executor/util/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import (
"encoding/base64"
"fmt"
"reflect"
"sort"
"strconv"
"strings"
Expand Down Expand Up @@ -369,3 +370,97 @@
}
return service.Name
}

var (
ErrorNotPointer = errors.New("must be a pointer")
ErrorNotSameType = errors.New("dst and src are not same type")
ErrorValueIsNil = errors.New("value is nil")
)

func MergeStruct(dst, src any) error {
dstTpy := reflect.TypeOf(dst)
if dstTpy.Kind() != reflect.Ptr {
return ErrorNotPointer
}

Check warning on line 384 in internal/tools/orchestrator/scheduler/executor/util/util.go

View check run for this annotation

Codecov / codecov/patch

internal/tools/orchestrator/scheduler/executor/util/util.go#L383-L384

Added lines #L383 - L384 were not covered by tests
dstTpy = dstTpy.Elem()

srcTpy := reflect.TypeOf(src)
if srcTpy.Kind() != reflect.Ptr {
return ErrorNotPointer
}

Check warning on line 390 in internal/tools/orchestrator/scheduler/executor/util/util.go

View check run for this annotation

Codecov / codecov/patch

internal/tools/orchestrator/scheduler/executor/util/util.go#L389-L390

Added lines #L389 - L390 were not covered by tests
srcTpy = srcTpy.Elem()

if srcTpy != dstTpy {
return ErrorNotSameType
}

Check warning on line 395 in internal/tools/orchestrator/scheduler/executor/util/util.go

View check run for this annotation

Codecov / codecov/patch

internal/tools/orchestrator/scheduler/executor/util/util.go#L394-L395

Added lines #L394 - L395 were not covered by tests

if isBaseType(srcTpy) {
return nil
}

dstVal := reflect.ValueOf(dst)
if dstVal.IsNil() {
return ErrorValueIsNil
}

Check warning on line 404 in internal/tools/orchestrator/scheduler/executor/util/util.go

View check run for this annotation

Codecov / codecov/patch

internal/tools/orchestrator/scheduler/executor/util/util.go#L403-L404

Added lines #L403 - L404 were not covered by tests
if dstVal.Kind() != reflect.Ptr {
return ErrorNotPointer
}

Check warning on line 407 in internal/tools/orchestrator/scheduler/executor/util/util.go

View check run for this annotation

Codecov / codecov/patch

internal/tools/orchestrator/scheduler/executor/util/util.go#L406-L407

Added lines #L406 - L407 were not covered by tests
dstVal = dstVal.Elem()

srcVal := reflect.ValueOf(src)
if srcVal.IsNil() {
return ErrorValueIsNil
}

Check warning on line 413 in internal/tools/orchestrator/scheduler/executor/util/util.go

View check run for this annotation

Codecov / codecov/patch

internal/tools/orchestrator/scheduler/executor/util/util.go#L412-L413

Added lines #L412 - L413 were not covered by tests
if srcVal.Kind() != reflect.Ptr {
return ErrorNotPointer
}

Check warning on line 416 in internal/tools/orchestrator/scheduler/executor/util/util.go

View check run for this annotation

Codecov / codecov/patch

internal/tools/orchestrator/scheduler/executor/util/util.go#L415-L416

Added lines #L415 - L416 were not covered by tests
srcVal = srcVal.Elem()

for i := 0; i < dstTpy.NumField(); i++ {
if dstTpy.Field(i).Type.Kind() == reflect.Ptr {
// source data is nil, skip merge
if srcVal.Field(i).IsNil() {
continue
}

// dst and src are not nil, continue recursively
if !dstVal.Field(i).IsNil() && !srcVal.Field(i).IsNil() {
if err := MergeStruct(dstVal.Field(i).Interface(), srcVal.Field(i).Interface()); err != nil {
return err
}

Check warning on line 430 in internal/tools/orchestrator/scheduler/executor/util/util.go

View check run for this annotation

Codecov / codecov/patch

internal/tools/orchestrator/scheduler/executor/util/util.go#L429-L430

Added lines #L429 - L430 were not covered by tests
continue
}

// dst is nil and src is not nil, set value directly
if dstVal.Field(i).IsNil() && !srcVal.Field(i).IsNil() {
dstVal.Field(i).Set(srcVal.Field(i))
continue
}

}
}
return nil
}

func isBaseType(typ reflect.Type) bool {
switch typ.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return true
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return true
case reflect.Float32, reflect.Float64:
return true
case reflect.Bool:
return true
case reflect.String:
return true
case reflect.Slice, reflect.Array:
return true
case reflect.Map:
return true
case reflect.Chan:
return true

Check warning on line 462 in internal/tools/orchestrator/scheduler/executor/util/util.go

View check run for this annotation

Codecov / codecov/patch

internal/tools/orchestrator/scheduler/executor/util/util.go#L449-L462

Added lines #L449 - L462 were not covered by tests
default:
return false
}
}
36 changes: 36 additions & 0 deletions internal/tools/orchestrator/scheduler/executor/util/util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,17 @@
package util

import (
"encoding/json"
"fmt"
"strings"
"testing"

"github.com/stretchr/testify/assert"
apiv1 "k8s.io/api/core/v1"

"github.com/erda-project/erda/apistructs"
"github.com/erda-project/erda/internal/tools/orchestrator/scheduler/executor/plugins/k8s/types"
"github.com/erda-project/erda/pkg/parser/diceyml"
)

func TestParsePreserveProjects(t *testing.T) {
Expand Down Expand Up @@ -209,3 +213,35 @@ func Test_ParseAnnotationFromEnv(t *testing.T) {
})
}
}

func TestMergeStructValue(t *testing.T) {

dstRunAsUser := int64(0)
want := `{"container":{"securityContext":{"runAsUser":0,"runAsGroup":1000}}}`
dst := apistructs.Service{
K8SSnippet: &diceyml.K8SSnippet{
Container: &diceyml.ContainerSnippet{
SecurityContext: &apiv1.SecurityContext{
RunAsUser: &dstRunAsUser,
},
},
},
}

src := apistructs.Service{
K8SSnippet: &diceyml.K8SSnippet{
Container: &diceyml.ContainerSnippet{
SecurityContext: &apiv1.SecurityContext{
RunAsUser: &types.DefaultContainerUserId,
RunAsGroup: &types.DefaultContainerGroupId,
},
},
},
}
err := MergeStruct(&dst, &src)
assert.NoError(t, err)

marshal, _ := json.Marshal(dst.K8SSnippet)
fmt.Println(string(marshal))
assert.Equal(t, want, string(marshal))
}
Loading