Merge pull request #17450 from danishprakash/add-group-entry

create: add entry to /etc/group via `--group-entry`
This commit is contained in:
OpenShift Merge Robot
2023-02-28 21:59:59 +01:00
committed by GitHub
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") createFlags.StringVar(&cf.PasswdEntry, passwdEntryName, "", "Entry to write to /etc/passwd")
_ = cmd.RegisterFlagCompletionFunc(passwdEntryName, completion.AutocompleteNone) _ = 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" decryptionKeysFlagName := "decryption-key"
createFlags.StringSliceVar( createFlags.StringSliceVar(
&cf.DecryptionKeys, &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-add
@@option group-entry
@@option health-cmd @@option health-cmd
@@option health-interval @@option health-interval

View File

@ -194,6 +194,8 @@ See [**Environment**](#environment) note below for precedence and examples.
@@option group-add @@option group-add
@@option group-entry
@@option health-cmd @@option health-cmd
@@option health-interval @@option health-interval

View File

@ -356,6 +356,8 @@ type ContainerMiscConfig struct {
CgroupsMode string `json:"cgroupsMode,omitempty"` CgroupsMode string `json:"cgroupsMode,omitempty"`
// Cgroup parent of the container. // Cgroup parent of the container.
CgroupParent string `json:"cgroupParent"` CgroupParent string `json:"cgroupParent"`
// GroupEntry specifies arbitrary data to append to a file.
GroupEntry string `json:"group_entry,omitempty"`
// LogPath log location // LogPath log location
LogPath string `json:"logPath"` LogPath string `json:"logPath"`
// LogTag is the tag used for logging // LogTag is the tag used for logging

View File

@ -2232,7 +2232,7 @@ func (c *Container) generateGroupEntry() (string, error) {
groupString += entry groupString += entry
addedGID = gid addedGID = gid
} }
if c.config.User != "" { if c.config.User != "" || c.config.GroupEntry != "" {
entry, err := c.generateUserGroupEntry(addedGID) entry, err := c.generateUserGroupEntry(addedGID)
if err != nil { if err != nil {
return "", err return "", err
@ -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 // Make an entry in /etc/group for the group the container was specified to run
// as. // as.
func (c *Container) generateUserGroupEntry(addedGID int) (string, error) { func (c *Container) generateUserGroupEntry(addedGID int) (string, error) {
if c.config.User == "" { if c.config.User == "" && c.config.GroupEntry == "" {
return "", nil return "", nil
} }
@ -2307,14 +2307,26 @@ func (c *Container) generateUserGroupEntry(addedGID int) (string, error) {
} }
// Check if the group already exists // 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 { if err != runcuser.ErrNoGroupEntries {
return "", err 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 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 // generatePasswdEntry generates an entry or entries into /etc/passwd as
// required by container configuration. // required by container configuration.
// Generally speaking, we will make an entry under two circumstances: // Generally speaking, we will make an entry under two circumstances:
@ -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 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 := c.config.PasswdEntry
s = strings.ReplaceAll(s, "$USERNAME", username) s = strings.ReplaceAll(s, "$USERNAME", username)
s = strings.ReplaceAll(s, "$UID", uid) s = strings.ReplaceAll(s, "$UID", uid)
@ -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). // read-only. In this case, the function will return nothing ("", "", nil).
func (c *Container) generatePasswdAndGroup() (string, string, error) { func (c *Container) generatePasswdAndGroup() (string, string, error) {
if !c.config.AddCurrentUserPasswdEntry && c.config.User == "" && if !c.config.AddCurrentUserPasswdEntry && c.config.User == "" &&
len(c.config.HostUsers) == 0 { len(c.config.HostUsers) == 0 && c.config.GroupEntry == "" {
return "", "", nil return "", "", nil
} }

View File

@ -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 // WithMountAllDevices sets the option to mount all of a privileged container's
// host devices // host devices
func WithMountAllDevices() CtrCreateOption { func WithMountAllDevices() CtrCreateOption {

View File

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

View File

@ -312,6 +312,9 @@ func createContainerOptions(rt *libpod.Runtime, s *specgen.SpecGenerator, pod *l
if s.PasswdEntry != "" { if s.PasswdEntry != "" {
options = append(options, libpod.WithPasswdEntry(s.PasswdEntry)) options = append(options, libpod.WithPasswdEntry(s.PasswdEntry))
} }
if s.GroupEntry != "" {
options = append(options, libpod.WithGroupEntry(s.GroupEntry))
}
if s.Privileged { if s.Privileged {
options = append(options, libpod.WithMountAllDevices()) options = append(options, libpod.WithMountAllDevices())

View File

@ -160,7 +160,7 @@ type ContainerBasicConfig struct {
// Conflicts with UtsNS if UtsNS is not set to private. // Conflicts with UtsNS if UtsNS is not set to private.
// Optional. // Optional.
Hostname string `json:"hostname,omitempty"` 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 // /etc/passwd file
HostUsers []string `json:"hostusers,omitempty"` HostUsers []string `json:"hostusers,omitempty"`
// Sysctl sets kernel parameters for the container // Sysctl sets kernel parameters for the container
@ -219,6 +219,8 @@ type ContainerBasicConfig struct {
Passwd *bool `json:"manage_password,omitempty"` Passwd *bool `json:"manage_password,omitempty"`
// PasswdEntry specifies arbitrary data to append to a file. // PasswdEntry specifies arbitrary data to append to a file.
PasswdEntry string `json:"passwd_entry,omitempty"` 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 // ContainerStorageConfig contains information on the storage configuration of a

View File

@ -858,6 +858,10 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions
s.PasswdEntry = c.PasswdEntry s.PasswdEntry = c.PasswdEntry
} }
if len(s.GroupEntry) == 0 || len(c.GroupEntry) != 0 {
s.GroupEntry = c.GroupEntry
}
return nil return nil
} }

View File

@ -153,4 +153,16 @@ USER 1000`, ALPINE)
Expect(run).Should(Exit(0)) Expect(run).Should(Exit(0))
Expect(run.OutputToString()).To(ContainSubstring("12345-12346-container user-/etc-12345")) 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"))
})
}) })