Skip to content

Commit

Permalink
feat: add ability to set uid and gid (#2024)
Browse files Browse the repository at this point in the history
## Description:
This allows users to change the user & group with which a container
starts

## Is this change user facing?
YES

## References (if applicable):
Closes #2000

Note this is a workaround to solve #2000 while
moby/moby#2259 remains open
  • Loading branch information
h4ck3rk3y committed Jan 8, 2024
1 parent 3988fe3 commit 2102164
Show file tree
Hide file tree
Showing 23 changed files with 349 additions and 4 deletions.
Expand Up @@ -538,6 +538,7 @@ func createStartServiceOperation(
cpuAllocationMillicpus := serviceConfig.GetCPUAllocationMillicpus()
memoryAllocationMegabytes := serviceConfig.GetMemoryAllocationMegabytes()
privateIPAddrPlaceholder := serviceConfig.GetPrivateIPAddrPlaceholder()
user := serviceConfig.GetUser()

// We replace the placeholder value with the actual private IP address
privateIPAddrStr := privateIpAddr.String()
Expand Down Expand Up @@ -691,7 +692,7 @@ func createStartServiceOperation(
fluentdLoggingDriverCnfg,
).WithRestartPolicy(
restartPolicy,
)
).WithUser(user)

if entrypointArgs != nil {
createAndStartArgsBuilder.WithEntrypointArgs(entrypointArgs)
Expand Down
@@ -1,6 +1,7 @@
package docker_manager

import (
"github.com/kurtosis-tech/kurtosis/container-engine-lib/lib/backend_interface/objects/service_user"
"net"

"github.com/docker/go-connections/nat"
Expand Down Expand Up @@ -32,6 +33,7 @@ type CreateAndStartContainerArgs struct {
containerInitEnabled bool
restartPolicy RestartPolicy
imageDownloadMode image_download_mode.ImageDownloadMode
user *service_user.ServiceUser
}

// Builder for creating CreateAndStartContainerArgs object
Expand Down Expand Up @@ -59,6 +61,7 @@ type CreateAndStartContainerArgsBuilder struct {
containerInitEnabled bool
restartPolicy RestartPolicy
imageDownloadMode image_download_mode.ImageDownloadMode
user *service_user.ServiceUser
}

/*
Expand Down Expand Up @@ -93,6 +96,7 @@ func NewCreateAndStartContainerArgsBuilder(dockerImage string, name string, netw
containerInitEnabled: false,
restartPolicy: NoRestart,
imageDownloadMode: image_download_mode.ImageDownloadMode_Missing,
user: nil,
}
}

Expand Down Expand Up @@ -121,6 +125,7 @@ func (builder *CreateAndStartContainerArgsBuilder) Build() *CreateAndStartContai
containerInitEnabled: builder.containerInitEnabled,
restartPolicy: builder.restartPolicy,
imageDownloadMode: builder.imageDownloadMode,
user: builder.user,
}
}

Expand Down Expand Up @@ -265,3 +270,8 @@ func (builder *CreateAndStartContainerArgsBuilder) WithFetchingLatestImageIfMiss
builder.imageDownloadMode = image_download_mode.ImageDownloadMode_Missing
return builder
}

func (builder *CreateAndStartContainerArgsBuilder) WithUser(user *service_user.ServiceUser) *CreateAndStartContainerArgsBuilder {
builder.user = user
return builder
}
Expand Up @@ -557,6 +557,11 @@ func (manager *DockerManager) CreateAndStartContainer(
usedPortsSet[port] = struct{}{}
}

var userStr string
if args.user != nil {
userStr = args.user.GetUIDGIDPairAsStr()
}

containerConfigPtr, err := manager.getContainerCfg(
dockerImage,
isInteractiveMode,
Expand All @@ -565,6 +570,7 @@ func (manager *DockerManager) CreateAndStartContainer(
args.cmdArgs,
args.envVariables,
args.labels,
userStr,
)
if err != nil {
return "", nil, stacktrace.Propagate(err, "Failed to configure container from service.")
Expand Down Expand Up @@ -1798,7 +1804,8 @@ func (manager *DockerManager) getContainerCfg(
entrypointArgs []string,
cmdArgs []string,
envVariables map[string]string,
labels map[string]string) (config *container.Config, err error) {
labels map[string]string,
user string) (config *container.Config, err error) {

envVariablesSlice := make([]string, 0, len(envVariables))
for key, val := range envVariables {
Expand All @@ -1808,7 +1815,7 @@ func (manager *DockerManager) getContainerCfg(
nodeConfigPtr := &container.Config{
Hostname: "",
Domainname: "",
User: "",
User: user,
AttachStdin: isInteractiveMode, // Analogous to `-a STDIN` option to `docker run`
AttachStdout: isInteractiveMode, // Analogous to `-a STDOUT` option to `docker run`
AttachStderr: isInteractiveMode, // Analogous to `-a STDERR` option to `docker run`
Expand Down
Expand Up @@ -3,6 +3,7 @@ package user_services_functions
import (
"context"
"fmt"
"github.com/kurtosis-tech/kurtosis/container-engine-lib/lib/backend_interface/objects/service_user"
"strings"

"github.com/kurtosis-tech/kurtosis/container-engine-lib/lib/backend_impls/kubernetes/kubernetes_kurtosis_backend/consts"
Expand Down Expand Up @@ -306,6 +307,7 @@ func createStartServiceOperation(
privateIPAddrPlaceholder := serviceConfig.GetPrivateIPAddrPlaceholder()
minCpuAllocationMilliCpus := serviceConfig.GetMinCPUAllocationMillicpus()
minMemoryAllocationMegabytes := serviceConfig.GetMinMemoryAllocationMegabytes()
user := serviceConfig.GetUser()

matchingObjectAndResources, found := servicesObjectsAndResources[serviceUuid]
if !found {
Expand Down Expand Up @@ -396,6 +398,7 @@ func createStartServiceOperation(
memoryAllocationMegabytes,
minCpuAllocationMilliCpus,
minMemoryAllocationMegabytes,
user,
)
if err != nil {
return nil, stacktrace.Propagate(err, "An error occurred creating the container specs for the user service pod with image '%v'", containerImageName)
Expand Down Expand Up @@ -632,6 +635,7 @@ func getUserServicePodContainerSpecs(
memoryAllocationMegabytes uint64,
minCpuAllocationMilliCpus uint64,
minMemoryAllocationMegabytes uint64,
user *service_user.ServiceUser,
) ([]apiv1.Container, error) {

var containerEnvVars []apiv1.EnvVar
Expand Down Expand Up @@ -692,6 +696,22 @@ func getUserServicePodContainerSpecs(
},
}

if user != nil {
uid := int64(user.GetUID())
// nolint: exhaustruct
securityContext := &apiv1.SecurityContext{
RunAsUser: &uid,
}

gid, gidIsSet := user.GetGID()
if gidIsSet {
gidAsInt64 := int64(gid)
securityContext.RunAsGroup = &gidAsInt64
}

containers[0].SecurityContext = securityContext
}

return containers, nil
}

Expand Down
Expand Up @@ -5,6 +5,7 @@ import (
"github.com/kurtosis-tech/kurtosis/container-engine-lib/lib/backend_interface/objects/image_build_spec"
"github.com/kurtosis-tech/kurtosis/container-engine-lib/lib/backend_interface/objects/port_spec"
"github.com/kurtosis-tech/kurtosis/container-engine-lib/lib/backend_interface/objects/service_directory"
"github.com/kurtosis-tech/kurtosis/container-engine-lib/lib/backend_interface/objects/service_user"
"github.com/kurtosis-tech/stacktrace"
)

Expand Down Expand Up @@ -48,6 +49,8 @@ type privateServiceConfig struct {
MinMemoryAllocationMegabytes uint64

Labels map[string]string

User *service_user.ServiceUser
}

func CreateServiceConfig(
Expand All @@ -66,6 +69,7 @@ func CreateServiceConfig(
minCpuMilliCores uint64,
minMemoryMegaBytes uint64,
labels map[string]string,
user *service_user.ServiceUser,
) (*ServiceConfig, error) {

if err := ValidateServiceConfigLabels(labels); err != nil {
Expand All @@ -89,6 +93,7 @@ func CreateServiceConfig(
MinCpuAllocationMilliCpus: minCpuMilliCores,
MinMemoryAllocationMegabytes: minMemoryMegaBytes,
Labels: labels,
User: user,
}
return &ServiceConfig{internalServiceConfig}, nil
}
Expand Down Expand Up @@ -151,6 +156,10 @@ func (serviceConfig *ServiceConfig) GetMinMemoryAllocationMegabytes() uint64 {
return serviceConfig.privateServiceConfig.MinMemoryAllocationMegabytes
}

func (serviceConfig *ServiceConfig) GetUser() *service_user.ServiceUser {
return serviceConfig.privateServiceConfig.User
}

func (serviceConfig *ServiceConfig) GetLabels() map[string]string {
return serviceConfig.privateServiceConfig.Labels
}
Expand Down
Expand Up @@ -76,6 +76,7 @@ func getServiceConfigForTest(t *testing.T, imageName string) *ServiceConfig {
"test-label-key": "test-label-value",
"test-second-label-key": "test-second-label-value",
},
nil,
)
require.NoError(t, err)
return serviceConfig
Expand Down
@@ -0,0 +1,46 @@
package service_user

import (
"fmt"
)

type UID int64
type GID int64

const (
defaultGidValue = -1
gidIsNotSet = false
)

type ServiceUser struct {
uid UID
gid GID
isGIDSet bool
}

func NewServiceUser(uid UID) *ServiceUser {
return &ServiceUser{uid: uid, gid: defaultGidValue, isGIDSet: gidIsNotSet}
}

func (su *ServiceUser) GetUID() UID {
return su.uid
}

func (su *ServiceUser) GetGID() (GID, bool) {
if !su.isGIDSet {
return 0, false
}
return su.gid, true
}

func (su *ServiceUser) SetGID(gid GID) {
su.gid = gid
su.isGIDSet = true
}

func (su *ServiceUser) GetUIDGIDPairAsStr() string {
if su.isGIDSet {
return fmt.Sprintf("%v:%v", su.uid, su.gid)
}
return fmt.Sprintf("%v", su.uid)
}
Expand Up @@ -321,6 +321,7 @@ func getServiceConfigForTest(t *testing.T, imageName string) *service.ServiceCon
"test-label-key": "test-label-value",
"test-second-label-key": "test-second-label-value",
},
nil,
)
require.NoError(t, err)
return serviceConfig
Expand Down
Expand Up @@ -178,6 +178,7 @@ func createStarlarkScript(
return script, nil
}

// TODO add support for User here
// Turns DockerCompose Service into Kurtosis ServiceConfigs and returns info needed for creating a valid starlark script
func convertComposeServicesToStarlarkInfo(composeServices types.Services) (
map[string]StarlarkServiceConfig, // Map of service names to Kurtosis ServiceConfig's
Expand Down
Expand Up @@ -1220,6 +1220,7 @@ func testServiceConfig(t *testing.T, imageName string) *service.ServiceConfig {
0,
0,
map[string]string{},
nil,
)
require.NoError(t, err)
return serviceConfig
Expand Down
Expand Up @@ -112,5 +112,6 @@ func KurtosisTypeConstructors() []*starlark.Builtin {
starlark.NewBuiltin(service_config.ServiceConfigTypeName, service_config.NewServiceConfigType().CreateBuiltin()),
starlark.NewBuiltin(service_config.ReadyConditionTypeName, service_config.NewReadyConditionType().CreateBuiltin()),
starlark.NewBuiltin(service_config.ImageBuildSpecTypeName, service_config.NewImageBuildSpecType().CreateBuiltin()),
starlark.NewBuiltin(service_config.UserTypeName, service_config.NewUserType().CreateBuiltin()),
}
}
Expand Up @@ -212,6 +212,7 @@ func replaceMagicStrings(
serviceConfig.GetMinCPUAllocationMillicpus(),
serviceConfig.GetMinMemoryAllocationMegabytes(),
serviceConfig.GetLabels(),
serviceConfig.GetUser(),
)
if err != nil {
return "", nil, stacktrace.Propagate(err, "An error occurred creating a service config")
Expand Down
Expand Up @@ -52,6 +52,7 @@ func TestAddServiceShared_EntryPointArgsRuntimeValueAreReplaced(t *testing.T) {
0,
0,
map[string]string{},
nil,
)
require.NoError(t, err)

Expand Down Expand Up @@ -94,6 +95,7 @@ func TestAddServiceShared_CmdArgsRuntimeValueAreReplaced(t *testing.T) {
0,
0,
map[string]string{},
nil,
)
require.NoError(t, err)

Expand Down Expand Up @@ -138,6 +140,7 @@ func TestAddServiceShared_EnvVarsWithRuntimeValueAreReplaced(t *testing.T) {
0,
0,
map[string]string{},
nil,
)
require.NoError(t, err)

Expand Down Expand Up @@ -183,6 +186,7 @@ func TestAddServiceShared_ServiceNameWithRuntimeValuesAreReplaced(t *testing.T)
0,
0,
map[string]string{},
nil,
)
require.NoError(t, err)

Expand Down
Expand Up @@ -270,6 +270,7 @@ func getServiceConfig(image string, filesArtifactExpansion *service_directory.Fi
0,
0,
map[string]string{},
nil,
)
if err != nil {
return nil, stacktrace.Propagate(err, "An error occurred creating service config")
Expand Down
Expand Up @@ -48,6 +48,7 @@ func (suite *KurtosisPlanInstructionTestSuite) TestAddService() {
0,
0,
map[string]string{},
nil,
)
require.NoError(suite.T(), err)

Expand Down
Expand Up @@ -64,6 +64,7 @@ func (suite *KurtosisPlanInstructionTestSuite) TestAddServices() {
0,
0,
map[string]string{},
nil,
)
require.NoError(suite.T(), err)

Expand All @@ -86,6 +87,7 @@ func (suite *KurtosisPlanInstructionTestSuite) TestAddServices() {
0,
0,
map[string]string{},
nil,
)
require.NoError(suite.T(), err)

Expand Down
Expand Up @@ -83,6 +83,7 @@ func (t *serviceConfigImageBuildSpecTestCase) Assert(typeValue builtin_argument.
0,
0,
map[string]string{},
nil,
)
require.NoError(t, err)
require.Equal(t, expectedServiceConfig, serviceConfig)
Expand Down
Expand Up @@ -60,6 +60,7 @@ func (t *serviceConfigMinimalTestCase) Assert(typeValue builtin_argument.Kurtosi
0,
0,
map[string]string{},
nil,
)
require.NoError(t, err)
require.Equal(t, expectedServiceConfig, serviceConfig)
Expand Down

0 comments on commit 2102164

Please sign in to comment.