diff options
-rw-r--r-- | cmd/podman/containers/run.go | 4 | ||||
-rwxr-xr-x | contrib/cirrus/setup_environment.sh | 5 | ||||
-rw-r--r-- | docs/source/markdown/podman-run.1.md | 5 | ||||
-rw-r--r-- | libpod/container_config.go | 2 | ||||
-rw-r--r-- | libpod/container_inspect.go | 2 | ||||
-rw-r--r-- | libpod/container_internal_linux.go | 63 | ||||
-rw-r--r-- | libpod/define/container_inspect.go | 2 | ||||
-rw-r--r-- | libpod/options.go | 11 | ||||
-rw-r--r-- | pkg/api/handlers/libpod/containers_create.go | 6 | ||||
-rw-r--r-- | pkg/api/handlers/utils/images.go | 2 | ||||
-rw-r--r-- | pkg/domain/entities/containers.go | 1 | ||||
-rw-r--r-- | pkg/domain/infra/abi/containers.go | 1 | ||||
-rw-r--r-- | pkg/specgen/generate/container_create.go | 3 | ||||
-rw-r--r-- | pkg/specgen/specgen.go | 2 | ||||
-rw-r--r-- | pkg/specgenutil/specgen.go | 3 | ||||
-rw-r--r-- | test/e2e/run_passwd_test.go | 12 | ||||
-rw-r--r-- | test/python/docker/compat/test_images.py | 1 | ||||
-rw-r--r-- | test/system/030-run.bats | 10 |
18 files changed, 106 insertions, 29 deletions
diff --git a/cmd/podman/containers/run.go b/cmd/podman/containers/run.go index cfb89ce57..b9a2c3bb5 100644 --- a/cmd/podman/containers/run.go +++ b/cmd/podman/containers/run.go @@ -83,6 +83,9 @@ func runFlags(cmd *cobra.Command) { _ = cmd.RegisterFlagCompletionFunc(gpuFlagName, completion.AutocompleteNone) _ = flags.MarkHidden("gpus") + passwdFlagName := "passwd" + flags.BoolVar(&runOpts.Passwd, passwdFlagName, true, "add entries to /etc/passwd and /etc/group") + if registry.IsRemote() { _ = flags.MarkHidden("preserve-fds") _ = flags.MarkHidden("conmon-pidfile") @@ -191,6 +194,7 @@ func run(cmd *cobra.Command, args []string) error { return err } s.RawImageName = rawImageName + s.Passwd = &runOpts.Passwd runOpts.Spec = s if _, err := createPodIfNecessary(cmd, s, cliVals.Net); err != nil { diff --git a/contrib/cirrus/setup_environment.sh b/contrib/cirrus/setup_environment.sh index 8f535c7e7..43c709228 100755 --- a/contrib/cirrus/setup_environment.sh +++ b/contrib/cirrus/setup_environment.sh @@ -118,6 +118,11 @@ fi case "$OS_RELEASE_ID" in ubuntu) ;; fedora) + # Force a crun version that has this fix: https://github.com/containers/crun/pull/819 + # FIXME: Remove once a fixed crun made its way into Fedora + if test "$OS_RELEASE_VER" == "35"; then + yum upgrade -y https://kojipkgs.fedoraproject.org//work/tasks/684/80280684/crun-1.3-2.fc35.x86_64.rpm + fi if ((CONTAINER==0)); then # All SELinux distros need this for systemd-in-a-container msg "Enabling container_manage_cgroup" diff --git a/docs/source/markdown/podman-run.1.md b/docs/source/markdown/podman-run.1.md index a6687e656..55642d5b3 100644 --- a/docs/source/markdown/podman-run.1.md +++ b/docs/source/markdown/podman-run.1.md @@ -762,6 +762,11 @@ Tune the host's OOM preferences for containers (accepts values from **-1000** to #### **--os**=*OS* Override the OS, defaults to hosts, of the image to be pulled. For example, `windows`. +#### **--passwd** + +Allow Podman to add entries to /etc/passwd and /etc/group when used in conjunction with the --user option. +This is used to override the Podman provided user setup in favor of entrypoint configurations such as libnss-extrausers. + #### **--personality**=*persona* Personality sets the execution domain via Linux personality(2). diff --git a/libpod/container_config.go b/libpod/container_config.go index adc585fa1..db65063b5 100644 --- a/libpod/container_config.go +++ b/libpod/container_config.go @@ -163,6 +163,8 @@ type ContainerRootFSConfig struct { // Volatile specifies whether the container storage can be optimized // at the cost of not syncing all the dirty files in memory. Volatile bool `json:"volatile,omitempty"` + // Passwd allows to user to override podman's passwd/group file setup + Passwd *bool `json:"passwd,omitempty"` } // ContainerSecurityConfig is an embedded sub-config providing security configuration diff --git a/libpod/container_inspect.go b/libpod/container_inspect.go index 439328ea8..b065dd1f9 100644 --- a/libpod/container_inspect.go +++ b/libpod/container_inspect.go @@ -377,6 +377,8 @@ func (c *Container) generateInspectContainerConfig(spec *spec.Spec) *define.Insp ctrConfig.Umask = c.config.Umask } + ctrConfig.Passwd = c.config.Passwd + return ctrConfig } diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go index c2ec02e57..edebe2393 100644 --- a/libpod/container_internal_linux.go +++ b/libpod/container_internal_linux.go @@ -1735,11 +1735,9 @@ func (c *Container) makeBindMounts() error { } if !c.config.UseImageHosts { - newHosts, err := c.generateHosts("/etc/hosts") - if err != nil { + if err := c.updateHosts("/etc/hosts"); err != nil { return errors.Wrapf(err, "error creating hosts file for container %s", c.ID()) } - c.state.BindMounts["/etc/hosts"] = newHosts } } @@ -1756,32 +1754,32 @@ func (c *Container) makeBindMounts() error { } } else { if !c.config.UseImageHosts && c.state.BindMounts["/etc/hosts"] == "" { - newHosts, err := c.generateHosts("/etc/hosts") - if err != nil { + if err := c.updateHosts("/etc/hosts"); err != nil { return errors.Wrapf(err, "error creating hosts file for container %s", c.ID()) } - c.state.BindMounts["/etc/hosts"] = newHosts } } // SHM is always added when we mount the container c.state.BindMounts["/dev/shm"] = c.config.ShmDir - newPasswd, newGroup, err := c.generatePasswdAndGroup() - if err != nil { - return errors.Wrapf(err, "error creating temporary passwd file for container %s", c.ID()) - } - if newPasswd != "" { - // Make /etc/passwd - // If it already exists, delete so we can recreate - delete(c.state.BindMounts, "/etc/passwd") - c.state.BindMounts["/etc/passwd"] = newPasswd - } - if newGroup != "" { - // Make /etc/group - // If it already exists, delete so we can recreate - delete(c.state.BindMounts, "/etc/group") - c.state.BindMounts["/etc/group"] = newGroup + if c.config.Passwd != nil && *c.config.Passwd { + newPasswd, newGroup, err := c.generatePasswdAndGroup() + if err != nil { + return errors.Wrapf(err, "error creating temporary passwd file for container %s", c.ID()) + } + if newPasswd != "" { + // Make /etc/passwd + // If it already exists, delete so we can recreate + delete(c.state.BindMounts, "/etc/passwd") + c.state.BindMounts["/etc/passwd"] = newPasswd + } + if newGroup != "" { + // Make /etc/group + // If it already exists, delete so we can recreate + delete(c.state.BindMounts, "/etc/group") + c.state.BindMounts["/etc/group"] = newGroup + } } // Make /etc/hostname @@ -2048,18 +2046,29 @@ func (c *Container) generateResolvConf() (string, error) { return destPath, nil } -// generateHosts creates a containers hosts file -func (c *Container) generateHosts(path string) (string, error) { +// updateHosts updates the container's hosts file +func (c *Container) updateHosts(path string) error { + var hosts string + orig, err := ioutil.ReadFile(path) if err != nil { - return "", err + // Ignore if the path does not exist + if !os.IsNotExist(err) { + return err + } + } else { + hosts = string(orig) } - hosts := string(orig) - hosts += c.getHosts() + hosts += c.getHosts() hosts = c.appendLocalhost(hosts) - return c.writeStringToRundir("hosts", hosts) + newHosts, err := c.writeStringToRundir("hosts", hosts) + if err != nil { + return err + } + c.state.BindMounts["/etc/hosts"] = newHosts + return nil } // based on networking mode we may want to append the localhost diff --git a/libpod/define/container_inspect.go b/libpod/define/container_inspect.go index a4d9bcf4f..ba73e4196 100644 --- a/libpod/define/container_inspect.go +++ b/libpod/define/container_inspect.go @@ -68,6 +68,8 @@ type InspectContainerConfig struct { Timeout uint `json:"Timeout"` // StopTimeout is time before container is stopped when calling stop StopTimeout uint `json:"StopTimeout"` + // Passwd determines whether or not podman can add entries to /etc/passwd and /etc/group + Passwd *bool `json:"Passwd,omitempty"` } // InspectRestartPolicy holds information about the container's restart policy. diff --git a/libpod/options.go b/libpod/options.go index e6fa987a8..85d7b4689 100644 --- a/libpod/options.go +++ b/libpod/options.go @@ -1794,6 +1794,17 @@ func WithHostDevice(dev []specs.LinuxDevice) CtrCreateOption { } } +// WithSelectedPasswordManagement makes it so that the container either does or does not setup /etc/passwd or /etc/group +func WithSelectedPasswordManagement(passwd *bool) CtrCreateOption { + return func(c *Container) error { + if c.valid { + return define.ErrCtrFinalized + } + c.config.Passwd = passwd + return nil + } +} + // Pod Creation Options // WithPodCreateCommand adds the full command plus arguments of the current diff --git a/pkg/api/handlers/libpod/containers_create.go b/pkg/api/handlers/libpod/containers_create.go index 77bfe7b50..d1841769a 100644 --- a/pkg/api/handlers/libpod/containers_create.go +++ b/pkg/api/handlers/libpod/containers_create.go @@ -19,11 +19,15 @@ import ( func CreateContainer(w http.ResponseWriter, r *http.Request) { runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime) var sg specgen.SpecGenerator + if err := json.NewDecoder(r.Body).Decode(&sg); err != nil { utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Decode()")) return } - + if sg.Passwd == nil { + t := true + sg.Passwd = &t + } warn, err := generate.CompleteSpec(r.Context(), runtime, &sg) if err != nil { utils.InternalServerError(w, err) diff --git a/pkg/api/handlers/utils/images.go b/pkg/api/handlers/utils/images.go index d874165e3..3f3f48193 100644 --- a/pkg/api/handlers/utils/images.go +++ b/pkg/api/handlers/utils/images.go @@ -35,7 +35,7 @@ func NormalizeToDockerHub(r *http.Request, nameOrID string) (string, error) { if errors.Cause(err) != storage.ErrImageUnknown { return "", fmt.Errorf("normalizing name for compat API: %v", err) } - } else if strings.HasPrefix(img.ID(), nameOrID) { + } else if strings.HasPrefix(img.ID(), strings.TrimPrefix(nameOrID, "sha256:")) { return img.ID(), nil } diff --git a/pkg/domain/entities/containers.go b/pkg/domain/entities/containers.go index 1677c067f..ae441b7f3 100644 --- a/pkg/domain/entities/containers.go +++ b/pkg/domain/entities/containers.go @@ -341,6 +341,7 @@ type ContainerRunOptions struct { Rm bool SigProxy bool Spec *specgen.SpecGenerator + Passwd bool } // ContainerRunReport describes the results of running diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go index d1af4a479..bf4dcff62 100644 --- a/pkg/domain/infra/abi/containers.go +++ b/pkg/domain/infra/abi/containers.go @@ -927,6 +927,7 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta for _, w := range warn { fmt.Fprintf(os.Stderr, "%s\n", w) } + rtSpec, spec, optsN, err := generate.MakeContainer(ctx, ic.Libpod, opts.Spec) if err != nil { return nil, err diff --git a/pkg/specgen/generate/container_create.go b/pkg/specgen/generate/container_create.go index 577a67bbe..1debf6c0e 100644 --- a/pkg/specgen/generate/container_create.go +++ b/pkg/specgen/generate/container_create.go @@ -489,5 +489,8 @@ func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen. if s.PidFile != "" { options = append(options, libpod.WithPidFile(s.PidFile)) } + + options = append(options, libpod.WithSelectedPasswordManagement(s.Passwd)) + return options, nil } diff --git a/pkg/specgen/specgen.go b/pkg/specgen/specgen.go index e650c1966..5a1cc1144 100644 --- a/pkg/specgen/specgen.go +++ b/pkg/specgen/specgen.go @@ -201,6 +201,8 @@ type ContainerBasicConfig struct { // UnsetEnvAll unsets all default environment variables from the image or from buildin // Optional. UnsetEnvAll bool `json:"unsetenvall,omitempty"` + // Passwd is a container run option that determines if we are validating users/groups before running the container + Passwd *bool `json:"manage_password,omitempty"` } // ContainerStorageConfig contains information on the storage configuration of a diff --git a/pkg/specgenutil/specgen.go b/pkg/specgenutil/specgen.go index 123c0073b..9a91b2893 100644 --- a/pkg/specgenutil/specgen.go +++ b/pkg/specgenutil/specgen.go @@ -698,6 +698,9 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions // Initcontainers s.InitContainerType = c.InitContainerType + + t := true + s.Passwd = &t return nil } diff --git a/test/e2e/run_passwd_test.go b/test/e2e/run_passwd_test.go index 6d1d26914..2207a50a8 100644 --- a/test/e2e/run_passwd_test.go +++ b/test/e2e/run_passwd_test.go @@ -125,4 +125,16 @@ USER 1000`, ALPINE) Expect(session).Should(Exit(0)) Expect(session.OutputToString()).To(Not(ContainSubstring("/etc/group"))) }) + + It("podman run --no-manage-passwd flag", func() { + run := podmanTest.Podman([]string{"run", "--user", "1234:1234", ALPINE, "cat", "/etc/passwd"}) + run.WaitWithDefaultTimeout() + Expect(run).Should(Exit(0)) + Expect(run.OutputToString()).To(ContainSubstring("1234:1234")) + + run = podmanTest.Podman([]string{"run", "--passwd=false", "--user", "1234:1234", ALPINE, "cat", "/etc/passwd"}) + run.WaitWithDefaultTimeout() + Expect(run).Should(Exit(0)) + Expect(run.OutputToString()).NotTo((ContainSubstring("1234:1234"))) + }) }) diff --git a/test/python/docker/compat/test_images.py b/test/python/docker/compat/test_images.py index 1e2b531b7..485a0e419 100644 --- a/test/python/docker/compat/test_images.py +++ b/test/python/docker/compat/test_images.py @@ -79,6 +79,7 @@ class TestImages(unittest.TestCase): # Add more images self.client.images.pull(constant.BB) self.assertEqual(len(self.client.images.list()), 2) + self.assertEqual(len(self.client.images.list(all=True)), 2) # List images with filter self.assertEqual(len(self.client.images.list(filters={"reference": "alpine"})), 1) diff --git a/test/system/030-run.bats b/test/system/030-run.bats index 6f1fa600a..55514305b 100644 --- a/test/system/030-run.bats +++ b/test/system/030-run.bats @@ -756,4 +756,14 @@ EOF is "$output" ".*TERM=abc" "missing TERM environment variable despite TERM being set on commandline" } +@test "podman run - no /etc/hosts" { + skip_if_rootless "cannot move /etc/hosts file as a rootless user" + tmpfile=$PODMAN_TMPDIR/hosts + mv /etc/hosts $tmpfile + run_podman '?' run --rm --add-host "foo.com:1.2.3.4" $IMAGE cat "/etc/hosts" + mv $tmpfile /etc/hosts + is "$status" 0 "podman run without /etc/hosts file should work" + is "$output" "1.2.3.4 foo.com.*" "users can add hosts even without /etc/hosts" +} + # vim: filetype=sh |