fix(WORKDIR): use the config.User for the new dir permissions (#2269)

WORKDIR ignores the currently set USER and creates the new directories
with the root user ownership.

This changes that, by executing a chown after the mkdir if needed, and
also handle the case where the provided USER is an uid and the passwd
file is not available to resolve to the username.

Fixes #2259

Signed-off-by: Aris Buzachis <buzachis.aris@gmail.com>

Signed-off-by: Aris Buzachis <buzachis.aris@gmail.com>
This commit is contained in:
Aris Buzachis 2022-09-29 04:18:40 +03:00 committed by GitHub
parent 4d077e2a40
commit 61312a95ae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 66 additions and 12 deletions

View File

@ -0,0 +1,41 @@
FROM debian:9.11
RUN groupadd -g 10000 bar
RUN useradd -c "Foo user" -u 10000 -g 10000 -m foo
# no passwd file
FROM scratch
# without a USER Set
WORKDIR /workdir/wo/user
USER 9999
WORKDIR /workdir/w/uid
USER 9999:9999
WORKDIR /workdir/w/uid_gid
USER 0
WORKDIR /workdir/w/root_uid
USER root
WORKDIR /workdir/w/root_username
# with passwd file
COPY --from=0 /etc/passwd /etc/passwd
COPY --from=0 /etc/group /etc/group
USER foo
WORKDIR /workdir/w/foo_username
USER foo:10000
WORKDIR /workdir/w/foo_username_gid
USER 10000
WORKDIR /workdir/w/foo_uid
USER 10000:10000
WORKDIR /workdir/w/foo_uid_gid
USER 10000:bar
WORKDIR /workdir/w/foo_uid_groupname

View File

@ -21,6 +21,7 @@ import (
"path/filepath" "path/filepath"
"github.com/GoogleContainerTools/kaniko/pkg/dockerfile" "github.com/GoogleContainerTools/kaniko/pkg/dockerfile"
"github.com/pkg/errors"
"github.com/GoogleContainerTools/kaniko/pkg/util" "github.com/GoogleContainerTools/kaniko/pkg/util"
v1 "github.com/google/go-containerregistry/pkg/v1" v1 "github.com/google/go-containerregistry/pkg/v1"
@ -35,7 +36,7 @@ type WorkdirCommand struct {
} }
// For testing // For testing
var mkdir = os.MkdirAll var mkdirAllWithPermissions = util.MkdirAllWithPermissions
func (w *WorkdirCommand) ExecuteCommand(config *v1.Config, buildArgs *dockerfile.BuildArgs) error { func (w *WorkdirCommand) ExecuteCommand(config *v1.Config, buildArgs *dockerfile.BuildArgs) error {
logrus.Info("Cmd: workdir") logrus.Info("Cmd: workdir")
@ -59,9 +60,21 @@ func (w *WorkdirCommand) ExecuteCommand(config *v1.Config, buildArgs *dockerfile
// Only create and snapshot the dir if it didn't exist already // Only create and snapshot the dir if it didn't exist already
w.snapshotFiles = []string{} w.snapshotFiles = []string{}
if _, err := os.Stat(config.WorkingDir); os.IsNotExist(err) { if _, err := os.Stat(config.WorkingDir); os.IsNotExist(err) {
logrus.Infof("Creating directory %s", config.WorkingDir) uid, gid := int64(-1), int64(-1)
if config.User != "" {
logrus.Debugf("Fetching uid and gid for USER '%s'", config.User)
uid, gid, err = util.GetUserGroup(config.User, replacementEnvs)
if err != nil {
return errors.Wrapf(err, "identifying uid and gid for user %s", config.User)
}
}
logrus.Infof("Creating directory %s with uid %d and gid %d", config.WorkingDir, uid, gid)
w.snapshotFiles = append(w.snapshotFiles, config.WorkingDir) w.snapshotFiles = append(w.snapshotFiles, config.WorkingDir)
return mkdir(config.WorkingDir, 0755) if err := mkdirAllWithPermissions(config.WorkingDir, 0755, uid, gid); err != nil {
return errors.Wrapf(err, "creating workdir %s", config.WorkingDir)
}
} }
return nil return nil
} }

View File

@ -83,17 +83,17 @@ var workdirTests = []struct {
} }
// For testing // For testing
func mockDir(p string, fi os.FileMode) error { func mockDir(path string, mode os.FileMode, uid, gid int64) error {
return nil return nil
} }
func TestWorkdirCommand(t *testing.T) { func TestWorkdirCommand(t *testing.T) {
// Mock out mkdir for testing. // Mock out mkdir for testing.
oldMkdir := mkdir oldMkdir := mkdirAllWithPermissions
mkdir = mockDir mkdirAllWithPermissions = mockDir
defer func() { defer func() {
mkdir = oldMkdir mkdirAllWithPermissions = oldMkdir
}() }()
cfg := &v1.Config{ cfg := &v1.Config{

View File

@ -442,8 +442,8 @@ func LookupUser(userStr string) (*user.User, error) {
userObj, err := user.Lookup(userStr) userObj, err := user.Lookup(userStr)
if err != nil { if err != nil {
unknownUserErr := new(user.UnknownUserError) unknownUserErr := new(user.UnknownUserError)
// only return if it's not an unknown user error // only return if it's not an unknown user error or the passwd file does not exist
if !errors.As(err, unknownUserErr) { if !errors.As(err, unknownUserErr) && !os.IsNotExist(err) {
return nil, err return nil, err
} }

View File

@ -348,7 +348,7 @@ func ExtractFile(dest string, hdr *tar.Header, tr io.Reader) error {
currFile.Close() currFile.Close()
case tar.TypeDir: case tar.TypeDir:
logrus.Tracef("Creating dir %s", path) logrus.Tracef("Creating dir %s", path)
if err := mkdirAllWithPermissions(path, mode, int64(uid), int64(gid)); err != nil { if err := MkdirAllWithPermissions(path, mode, int64(uid), int64(gid)); err != nil {
return err return err
} }
@ -663,7 +663,7 @@ func CopyDir(src, dest string, context FileContext, uid, gid int64) ([]string, e
mode := fi.Mode() mode := fi.Mode()
uid, gid := DetermineTargetFileOwnership(fi, uid, gid) uid, gid := DetermineTargetFileOwnership(fi, uid, gid)
if err := mkdirAllWithPermissions(destPath, mode, uid, gid); err != nil { if err := MkdirAllWithPermissions(destPath, mode, uid, gid); err != nil {
return nil, err return nil, err
} }
} else if IsSymlink(fi) { } else if IsSymlink(fi) {
@ -806,7 +806,7 @@ func Volumes() []string {
return volumes return volumes
} }
func mkdirAllWithPermissions(path string, mode os.FileMode, uid, gid int64) error { func MkdirAllWithPermissions(path string, mode os.FileMode, uid, gid int64) error {
// Check if a file already exists on the path, if yes then delete it // Check if a file already exists on the path, if yes then delete it
info, err := os.Stat(path) info, err := os.Stat(path)
if err == nil && !info.IsDir() { if err == nil && !info.IsDir() {