Skip to content

Commit 04cd64a

Browse files
committed
improved custom user id selection logic for the debug command
Signed-off-by: Kyle Quest <[email protected]>
1 parent ac2b15a commit 04cd64a

File tree

2 files changed

+121
-6
lines changed

2 files changed

+121
-6
lines changed

pkg/app/master/command/debug/handle_kubernetes_runtime.go

Lines changed: 113 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@ import (
88
"io/ioutil"
99
"net/http"
1010
"os"
11+
"strconv"
1112
"strings"
1213
"time"
1314

15+
dockerapi "github.com/fsouza/go-dockerclient"
1416
log "github.com/sirupsen/logrus"
1517
corev1 "k8s.io/api/core/v1"
1618
apierrors "k8s.io/apimachinery/pkg/api/errors"
@@ -24,6 +26,7 @@ import (
2426

2527
"github.com/mintoolkit/mint/pkg/app"
2628
"github.com/mintoolkit/mint/pkg/app/master/command"
29+
"github.com/mintoolkit/mint/pkg/app/master/inspectors/image"
2730
"github.com/mintoolkit/mint/pkg/util/jsonutil"
2831
)
2932

@@ -33,6 +36,7 @@ func HandleKubernetesRuntime(
3336
xc *app.ExecutionContext,
3437
gparams *command.GenericParams,
3538
commandParams *CommandParams,
39+
dockerClient *dockerapi.Client,
3640
sid string,
3741
debugContainerName string) {
3842
logger = logger.WithFields(
@@ -484,17 +488,121 @@ func HandleKubernetesRuntime(
484488
}
485489

486490
targetIsNonRoot := runAsNonRoot()
487-
runAsUserVal := runAsUser(targetIsNonRoot)
488-
if targetIsNonRoot && runAsUserVal == nil {
489-
//TODO: first, try getting the user identity from the target's container image
490-
runAsUserVal = &defaultNonRootUser
491-
}
491+
492492
runAsGroupVal := runAsGroup(targetIsNonRoot)
493493
if targetIsNonRoot && runAsGroupVal == nil && commandParams.UID < 0 {
494494
//don't use the default group if UID is set
495495
runAsGroupVal = &defaultNonRootGroup
496496
}
497497

498+
runAsUserVal := runAsUser(targetIsNonRoot)
499+
if targetIsNonRoot && runAsUserVal == nil {
500+
//first, try getting the user identity from the target's container image
501+
var userFromImage string
502+
if targetContainer.Image != "" && dockerClient != nil {
503+
//TODO: improve
504+
//v1 version is very hacky:
505+
//* it expects the Docker container runtime locally
506+
//* it expects the target container image to be available locally
507+
//* it expects the target container images to be pullable (with no auth)
508+
imageInspector, err := image.NewInspector(dockerClient, targetContainer.Image)
509+
if err == nil {
510+
noImage, err := imageInspector.NoImage()
511+
if err == nil {
512+
var foundImage bool
513+
if noImage {
514+
if err := imageInspector.Pull(true, "", "", ""); err != nil {
515+
logger.WithError(err).Trace("imageInspector.Pull")
516+
}
517+
518+
imageInspector, err = image.NewInspector(dockerClient, targetContainer.Image)
519+
if err == nil {
520+
noImage, err = imageInspector.NoImage()
521+
if err == nil {
522+
if !noImage {
523+
foundImage = true
524+
}
525+
} else {
526+
logger.WithError(err).Trace("imageInspector.NoImage")
527+
}
528+
} else {
529+
logger.WithError(err).Trace("image.NewInspector")
530+
}
531+
} else {
532+
foundImage = true
533+
}
534+
535+
if foundImage {
536+
if err := imageInspector.Inspect(); err == nil {
537+
userFromImage = imageInspector.ImageInfo.Config.User
538+
} else {
539+
logger.WithError(err).Trace("imageInspector.Inspect")
540+
}
541+
}
542+
543+
} else {
544+
logger.WithError(err).Trace("imageInspector.NoImage")
545+
}
546+
} else {
547+
logger.WithError(err).Trace("image.NewInspector")
548+
}
549+
}
550+
551+
uid := int64(-1)
552+
gid := int64(-1)
553+
if userFromImage != "" {
554+
var uidStr string
555+
var gidStr string
556+
if strings.Contains(userFromImage, ":") {
557+
parts := strings.SplitN(userFromImage, ":", 2)
558+
uidStr = parts[0]
559+
gidStr = parts[1]
560+
} else {
561+
uidStr = userFromImage
562+
}
563+
564+
uid, err = strconv.ParseInt(uidStr, 10, 64)
565+
if err != nil {
566+
logger.WithError(err).Tracef("strconv.ParseUint(uidStr=%s)", uidStr)
567+
uid = -1
568+
}
569+
570+
if gidStr != "" {
571+
gid, err = strconv.ParseInt(gidStr, 10, 64)
572+
if err != nil {
573+
logger.WithError(err).Tracef("strconv.ParseUint(gidStr=%s)", gidStr)
574+
gid = -1
575+
}
576+
}
577+
578+
logger.WithFields(
579+
log.Fields{
580+
"data": userFromImage,
581+
"image": targetContainer.Image,
582+
"uid.str": uidStr,
583+
"gid.str": gidStr,
584+
"uid": uid,
585+
"gid": gid,
586+
}).Trace("user.from.target.image")
587+
}
588+
589+
if uid > -1 {
590+
runAsUserVal = &uid
591+
logger.Debugf("using.target.image.user=%v", uid)
592+
} else {
593+
runAsUserVal = &defaultNonRootUser
594+
}
595+
596+
if gid == -1 {
597+
gid = uid
598+
}
599+
600+
if runAsGroupVal == &defaultNonRootGroup && gid > -1 {
601+
runAsGroupVal = &gid
602+
logger.Debugf("using.target.image.user.group=%v", gid)
603+
}
604+
}
605+
498606
var doRunAsNonRoot bool
499607
if targetIsNonRoot && commandParams.DoFallbackToTargetUser {
500608
doRunAsNonRoot = true

pkg/app/master/command/debug/handler.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,11 +112,18 @@ func OnCommand(
112112

113113
HandleDockerRuntime(logger, xc, gparams, commandParams, client, sid, debugContainerName)
114114
case KubernetesRuntime:
115+
//hacky v1... using docker client to lookup image info
116+
//todo: use another way to get k8s container image info
117+
client, err := dockerclient.New(gparams.ClientConfig)
118+
if err != nil {
119+
logger.WithError(err).Tracef("k8s.runtime.docker.client.error")
120+
}
121+
115122
if gparams.Debug {
116123
version.Print(xc, Name, logger, nil, false, gparams.InContainer, gparams.IsDSImage)
117124
}
118125

119-
HandleKubernetesRuntime(logger, xc, gparams, commandParams, sid, debugContainerName)
126+
HandleKubernetesRuntime(logger, xc, gparams, commandParams, client, sid, debugContainerName)
120127
case ContainerdRuntime:
121128
if gparams.Debug {
122129
version.Print(xc, Name, logger, nil, false, gparams.InContainer, gparams.IsDSImage)

0 commit comments

Comments
 (0)