create: add support for --group-entry

* add test
* update documentation

Signed-off-by: danishprakash <danish.prakash@suse.com>
This commit is contained in:
danishprakash
2023-02-09 18:20:36 +05:30
parent 166f3dfc1e
commit 828708bac2
12 changed files with 72 additions and 6 deletions

View File

@ -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,

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -354,6 +354,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

View File

@ -2226,7 +2226,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
@ -2281,7 +2281,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
}
@ -2301,14 +2301,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:
@ -2488,7 +2500,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)
@ -2512,7 +2524,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
}

View File

@ -2277,6 +2277,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 {

View File

@ -301,6 +301,7 @@ type ContainerCreateOptions struct {
CgroupConf []string
GroupEntry string
PasswdEntry string
}

View File

@ -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())

View File

@ -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
@ -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

View File

@ -848,6 +848,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
}

View File

@ -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"))
})
})