aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/podman/common/create.go4
-rw-r--r--docs/source/markdown/podman-create.1.md6
-rw-r--r--docs/source/markdown/podman-run.1.md6
-rw-r--r--libpod/container_config.go2
-rw-r--r--libpod/container_internal_linux.go19
-rw-r--r--libpod/options.go13
-rw-r--r--pkg/domain/entities/pods.go2
-rw-r--r--pkg/specgen/generate/container_create.go3
-rw-r--r--pkg/specgen/specgen.go2
-rw-r--r--pkg/specgenutil/specgen.go5
-rw-r--r--test/e2e/run_passwd_test.go12
11 files changed, 74 insertions, 0 deletions
diff --git a/cmd/podman/common/create.go b/cmd/podman/common/create.go
index 8a3f02036..309bbda59 100644
--- a/cmd/podman/common/create.go
+++ b/cmd/podman/common/create.go
@@ -630,6 +630,10 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions,
)
_ = cmd.RegisterFlagCompletionFunc(chrootDirsFlagName, completion.AutocompleteDefault)
+ passwdEntryName := "passwd-entry"
+ createFlags.StringVar(&cf.PasswdEntry, passwdEntryName, "", "Entry to write to /etc/passwd")
+ _ = cmd.RegisterFlagCompletionFunc(passwdEntryName, completion.AutocompleteNone)
+
if registry.IsRemote() {
_ = createFlags.MarkHidden("env-host")
_ = createFlags.MarkHidden("http-proxy")
diff --git a/docs/source/markdown/podman-create.1.md b/docs/source/markdown/podman-create.1.md
index c4d27e321..9af7174fc 100644
--- a/docs/source/markdown/podman-create.1.md
+++ b/docs/source/markdown/podman-create.1.md
@@ -755,6 +755,12 @@ Tune the host's OOM preferences for containers (accepts -1000 to 1000)
#### **--os**=*OS*
Override the OS, defaults to hosts, of the image to be pulled. For example, `windows`.
+#### **--passwd-entry**=*ENTRY*
+
+Customize the entry that is written to the `/etc/passwd` file within the container when `--passwd` is used.
+
+The variables $USERNAME, $UID, $GID, $NAME, $HOME are automatically replaced with their value at runtime.
+
#### **--personality**=*persona*
Personality sets the execution domain via Linux personality(2).
diff --git a/docs/source/markdown/podman-run.1.md b/docs/source/markdown/podman-run.1.md
index e4ccd0368..ecb24ba6d 100644
--- a/docs/source/markdown/podman-run.1.md
+++ b/docs/source/markdown/podman-run.1.md
@@ -787,6 +787,12 @@ Override the OS, defaults to hosts, of the image to be pulled. For example, `win
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.
+#### **--passwd-entry**=*ENTRY*
+
+Customize the entry that is written to the `/etc/passwd` file within the container when `--passwd` is used.
+
+The variables $USERNAME, $UID, $GID, $NAME, $HOME are automatically replaced with their value at runtime.
+
#### **--personality**=*persona*
Personality sets the execution domain via Linux personality(2).
diff --git a/libpod/container_config.go b/libpod/container_config.go
index ea644764c..8500c6db9 100644
--- a/libpod/container_config.go
+++ b/libpod/container_config.go
@@ -404,6 +404,8 @@ type ContainerMiscConfig struct {
// InitContainerType specifies if the container is an initcontainer
// and if so, what type: always or once are possible non-nil entries
InitContainerType string `json:"init_container_type,omitempty"`
+ // PasswdEntry specifies arbitrary data to append to a file.
+ PasswdEntry string `json:"passwd_entry,omitempty"`
}
// InfraInherit contains the compatible options inheritable from the infra container
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index 11ca169ca..9369b746c 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -2724,6 +2724,9 @@ func (c *Container) userPasswdEntry(u *user.User) (string, error) {
if !hasHomeSet {
c.config.Spec.Process.Env = append(c.config.Spec.Process.Env, fmt.Sprintf("HOME=%s", homeDir))
}
+ if c.config.PasswdEntry != "" {
+ return c.passwdEntry(u.Username, u.Uid, u.Gid, u.Name, homeDir), nil
+ }
return fmt.Sprintf("%s:*:%s:%s:%s:%s:/bin/sh\n", u.Username, u.Uid, u.Gid, u.Name, homeDir), nil
}
@@ -2775,9 +2778,25 @@ func (c *Container) generateUserPasswdEntry(addedUID int) (string, int, int, err
gid = group.Gid
}
}
+
+ if c.config.PasswdEntry != "" {
+ entry := c.passwdEntry(fmt.Sprintf("%d", uid), fmt.Sprintf("%d", uid), fmt.Sprintf("%d", gid), "container user", c.WorkingDir())
+ return entry, int(uid), gid, nil
+ }
+
return fmt.Sprintf("%d:*:%d:%d:container user:%s:/bin/sh\n", uid, uid, gid, c.WorkingDir()), int(uid), gid, nil
}
+func (c *Container) passwdEntry(username string, uid, gid, name, homeDir string) string {
+ s := c.config.PasswdEntry
+ s = strings.Replace(s, "$USERNAME", username, -1)
+ s = strings.Replace(s, "$UID", uid, -1)
+ s = strings.Replace(s, "$GID", gid, -1)
+ s = strings.Replace(s, "$NAME", name, -1)
+ s = strings.Replace(s, "$HOME", homeDir, -1)
+ return s + "\n"
+}
+
// generatePasswdAndGroup generates container-specific passwd and group files
// iff g.config.User is a number or we are configured to make a passwd entry for
// the current user or the user specified HostsUsers
diff --git a/libpod/options.go b/libpod/options.go
index 2e5454393..6c4b4cc42 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -2051,3 +2051,16 @@ func WithChrootDirs(dirs []string) CtrCreateOption {
return nil
}
}
+
+// WithPasswdEntry sets the entry to write to the /etc/passwd file.
+func WithPasswdEntry(passwdEntry string) CtrCreateOption {
+ return func(ctr *Container) error {
+ if ctr.valid {
+ return define.ErrCtrFinalized
+ }
+
+ ctr.config.PasswdEntry = passwdEntry
+
+ return nil
+ }
+}
diff --git a/pkg/domain/entities/pods.go b/pkg/domain/entities/pods.go
index f1d445c4b..1e25e0872 100644
--- a/pkg/domain/entities/pods.go
+++ b/pkg/domain/entities/pods.go
@@ -272,6 +272,8 @@ type ContainerCreateOptions struct {
Net *NetOptions `json:"net,omitempty"`
CgroupConf []string
+
+ PasswdEntry string
}
func NewInfraContainerCreateOptions() ContainerCreateOptions {
diff --git a/pkg/specgen/generate/container_create.go b/pkg/specgen/generate/container_create.go
index 6a611e854..b85a87742 100644
--- a/pkg/specgen/generate/container_create.go
+++ b/pkg/specgen/generate/container_create.go
@@ -286,6 +286,9 @@ func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen.
if s.Volatile {
options = append(options, libpod.WithVolatile())
}
+ if s.PasswdEntry != "" {
+ options = append(options, libpod.WithPasswdEntry(s.PasswdEntry))
+ }
useSystemd := false
switch s.Systemd {
diff --git a/pkg/specgen/specgen.go b/pkg/specgen/specgen.go
index dfac1d457..79e20667b 100644
--- a/pkg/specgen/specgen.go
+++ b/pkg/specgen/specgen.go
@@ -206,6 +206,8 @@ type ContainerBasicConfig struct {
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"`
+ // PasswdEntry specifies arbitrary data to append to a file.
+ PasswdEntry string `json:"passwd_entry,omitempty"`
}
// ContainerStorageConfig contains information on the storage configuration of a
diff --git a/pkg/specgenutil/specgen.go b/pkg/specgenutil/specgen.go
index 7d4fca846..42b66d909 100644
--- a/pkg/specgenutil/specgen.go
+++ b/pkg/specgenutil/specgen.go
@@ -832,6 +832,11 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions
if s.Passwd == nil {
s.Passwd = &t
}
+
+ if len(s.PasswdEntry) == 0 || len(c.PasswdEntry) != 0 {
+ s.PasswdEntry = c.PasswdEntry
+ }
+
return nil
}
diff --git a/test/e2e/run_passwd_test.go b/test/e2e/run_passwd_test.go
index 4c97e665a..ce6c6ffda 100644
--- a/test/e2e/run_passwd_test.go
+++ b/test/e2e/run_passwd_test.go
@@ -137,4 +137,16 @@ USER 1000`, ALPINE)
Expect(run).Should(Exit(0))
Expect(run.OutputToString()).NotTo((ContainSubstring("1234:1234")))
})
+
+ It("podman run --passwd-entry flag", func() {
+ // Test that the line we add doesn't contain anything else than what is specified
+ run := podmanTest.Podman([]string{"run", "--user", "1234:1234", "--passwd-entry=FOO", ALPINE, "grep", "^FOO$", "/etc/passwd"})
+ run.WaitWithDefaultTimeout()
+ Expect(run).Should(Exit(0))
+
+ run = podmanTest.Podman([]string{"run", "--user", "12345:12346", "-w", "/etc", "--passwd-entry=$UID-$GID-$NAME-$HOME-$USERNAME", ALPINE, "cat", "/etc/passwd"})
+ run.WaitWithDefaultTimeout()
+ Expect(run).Should(Exit(0))
+ Expect(run.OutputToString()).To(ContainSubstring("12345-12346-container user-/etc-12345"))
+ })
})