Skip to content

Commit

Permalink
Merge pull request containers#17450 from danishprakash/add-group-entry
Browse files Browse the repository at this point in the history
create: add entry to /etc/group via `--group-entry`
  • Loading branch information
openshift-merge-robot authored Feb 28, 2023
2 parents 773f0f5 + 828708b commit 02a77d2
Show file tree
Hide file tree
Showing 12 changed files with 72 additions and 6 deletions.
4 changes: 4 additions & 0 deletions cmd/podman/common/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -604,6 +604,10 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions,
createFlags.StringVar(&cf.PasswdEntry, passwdEntryName, "", "Entry to write to /etc/passwd")
_ = cmd.RegisterFlagCompletionFunc(passwdEntryName, completion.AutocompleteNone)

groupEntryName := "group-entry"
createFlags.StringVar(&cf.GroupEntry, groupEntryName, "", "Entry to write to /etc/group")
_ = cmd.RegisterFlagCompletionFunc(groupEntryName, completion.AutocompleteNone)

decryptionKeysFlagName := "decryption-key"
createFlags.StringSliceVar(
&cf.DecryptionKeys,
Expand Down
9 changes: 9 additions & 0 deletions docs/source/markdown/options/group-entry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
####> This option file is used in:
####> podman create, run
####> If file is edited, make sure the changes
####> are applicable to all of those.
#### **--group-entry**=*ENTRY*

Customize the entry that is written to the `/etc/group` file within the container when `--user` is used.

The variables $GROUPNAME, $GID, and $USERLIST are automatically replaced with their value at runtime if present.
2 changes: 2 additions & 0 deletions docs/source/markdown/podman-create.1.md.in
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,8 @@ See [**Environment**](#environment) note below for precedence and examples.

@@option group-add

@@option group-entry

@@option health-cmd

@@option health-interval
Expand Down
2 changes: 2 additions & 0 deletions docs/source/markdown/podman-run.1.md.in
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,8 @@ See [**Environment**](#environment) note below for precedence and examples.

@@option group-add

@@option group-entry

@@option health-cmd

@@option health-interval
Expand Down
2 changes: 2 additions & 0 deletions libpod/container_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,8 @@ type ContainerMiscConfig struct {
CgroupsMode string `json:"cgroupsMode,omitempty"`
// Cgroup parent of the container.
CgroupParent string `json:"cgroupParent"`
// GroupEntry specifies arbitrary data to append to a file.
GroupEntry string `json:"group_entry,omitempty"`
// LogPath log location
LogPath string `json:"logPath"`
// LogTag is the tag used for logging
Expand Down
22 changes: 17 additions & 5 deletions libpod/container_internal_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -2232,7 +2232,7 @@ func (c *Container) generateGroupEntry() (string, error) {
groupString += entry
addedGID = gid
}
if c.config.User != "" {
if c.config.User != "" || c.config.GroupEntry != "" {
entry, err := c.generateUserGroupEntry(addedGID)
if err != nil {
return "", err
Expand Down Expand Up @@ -2287,7 +2287,7 @@ func (c *Container) generateCurrentUserGroupEntry() (string, int, error) {
// Make an entry in /etc/group for the group the container was specified to run
// as.
func (c *Container) generateUserGroupEntry(addedGID int) (string, error) {
if c.config.User == "" {
if c.config.User == "" && c.config.GroupEntry == "" {
return "", nil
}

Expand All @@ -2307,14 +2307,26 @@ func (c *Container) generateUserGroupEntry(addedGID int) (string, error) {
}

// Check if the group already exists
_, err = lookup.GetGroup(c.state.Mountpoint, group)
g, err := lookup.GetGroup(c.state.Mountpoint, group)
if err != runcuser.ErrNoGroupEntries {
return "", err
}

if c.config.GroupEntry != "" {
return c.groupEntry(g.Name, strconv.Itoa(g.Gid), g.List), nil
}

return fmt.Sprintf("%d:x:%d:%s\n", gid, gid, splitUser[0]), nil
}

func (c *Container) groupEntry(groupname, gid string, list []string) string {
s := c.config.GroupEntry
s = strings.ReplaceAll(s, "$GROUPNAME", groupname)
s = strings.ReplaceAll(s, "$GID", gid)
s = strings.ReplaceAll(s, "$USERLIST", strings.Join(list, ","))
return s + "\n"
}

// generatePasswdEntry generates an entry or entries into /etc/passwd as
// required by container configuration.
// Generally speaking, we will make an entry under two circumstances:
Expand Down Expand Up @@ -2494,7 +2506,7 @@ func (c *Container) generateUserPasswdEntry(addedUID int) (string, error) {
return fmt.Sprintf("%d:*:%d:%d:container user:%s:/bin/sh\n", uid, uid, gid, c.WorkingDir()), nil
}

func (c *Container) passwdEntry(username string, uid, gid, name, homeDir string) string {
func (c *Container) passwdEntry(username, uid, gid, name, homeDir string) string {
s := c.config.PasswdEntry
s = strings.ReplaceAll(s, "$USERNAME", username)
s = strings.ReplaceAll(s, "$UID", uid)
Expand All @@ -2518,7 +2530,7 @@ func (c *Container) passwdEntry(username string, uid, gid, name, homeDir string)
// read-only. In this case, the function will return nothing ("", "", nil).
func (c *Container) generatePasswdAndGroup() (string, string, error) {
if !c.config.AddCurrentUserPasswdEntry && c.config.User == "" &&
len(c.config.HostUsers) == 0 {
len(c.config.HostUsers) == 0 && c.config.GroupEntry == "" {
return "", "", nil
}

Expand Down
13 changes: 13 additions & 0 deletions libpod/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -2293,6 +2293,19 @@ func WithPasswdEntry(passwdEntry string) CtrCreateOption {
}
}

// WithGroupEntry sets the entry to write to the /etc/group file.
func WithGroupEntry(groupEntry string) CtrCreateOption {
return func(ctr *Container) error {
if ctr.valid {
return define.ErrCtrFinalized
}

ctr.config.GroupEntry = groupEntry

return nil
}
}

// WithMountAllDevices sets the option to mount all of a privileged container's
// host devices
func WithMountAllDevices() CtrCreateOption {
Expand Down
1 change: 1 addition & 0 deletions pkg/domain/entities/pods.go
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,7 @@ type ContainerCreateOptions struct {

CgroupConf []string

GroupEntry string
PasswdEntry string
}

Expand Down
3 changes: 3 additions & 0 deletions pkg/specgen/generate/container_create.go
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,9 @@ func createContainerOptions(rt *libpod.Runtime, s *specgen.SpecGenerator, pod *l
if s.PasswdEntry != "" {
options = append(options, libpod.WithPasswdEntry(s.PasswdEntry))
}
if s.GroupEntry != "" {
options = append(options, libpod.WithGroupEntry(s.GroupEntry))
}

if s.Privileged {
options = append(options, libpod.WithMountAllDevices())
Expand Down
4 changes: 3 additions & 1 deletion pkg/specgen/specgen.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ type ContainerBasicConfig struct {
// Conflicts with UtsNS if UtsNS is not set to private.
// Optional.
Hostname string `json:"hostname,omitempty"`
// HostUses is a list of host usernames or UIDs to add to the container
// HostUsers is a list of host usernames or UIDs to add to the container
// /etc/passwd file
HostUsers []string `json:"hostusers,omitempty"`
// Sysctl sets kernel parameters for the container
Expand Down Expand Up @@ -219,6 +219,8 @@ type ContainerBasicConfig struct {
Passwd *bool `json:"manage_password,omitempty"`
// PasswdEntry specifies arbitrary data to append to a file.
PasswdEntry string `json:"passwd_entry,omitempty"`
// GroupEntry specifies arbitrary data to append to a file.
GroupEntry string `json:"group_entry,omitempty"`
}

// ContainerStorageConfig contains information on the storage configuration of a
Expand Down
4 changes: 4 additions & 0 deletions pkg/specgenutil/specgen.go
Original file line number Diff line number Diff line change
Expand Up @@ -858,6 +858,10 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions
s.PasswdEntry = c.PasswdEntry
}

if len(s.GroupEntry) == 0 || len(c.GroupEntry) != 0 {
s.GroupEntry = c.GroupEntry
}

return nil
}

Expand Down
12 changes: 12 additions & 0 deletions test/e2e/run_passwd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,4 +153,16 @@ USER 1000`, ALPINE)
Expect(run).Should(Exit(0))
Expect(run.OutputToString()).To(ContainSubstring("12345-12346-container user-/etc-12345"))
})

It("podman run --group-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", "--group-entry=FOO", ALPINE, "grep", "^FOO$", "/etc/group"})
run.WaitWithDefaultTimeout()
Expect(run).Should(Exit(0))

run = podmanTest.Podman([]string{"run", "--user", "12345:12346", "--group-entry=$GID", ALPINE, "tail", "/etc/group"})
run.WaitWithDefaultTimeout()
Expect(run).Should(Exit(0))
Expect(run.OutputToString()).To(ContainSubstring("12346"))
})
})

0 comments on commit 02a77d2

Please sign in to comment.