Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The --user option has inconsistent effects on the container passwd and group entries. #18903

Open
justinjereza opened this issue Jun 15, 2023 · 18 comments
Labels
kind/bug Categorizes issue or PR as related to a bug.

Comments

@justinjereza
Copy link

justinjereza commented Jun 15, 2023

Issue Description

I've discussed this with @cevich on IRC and he saw the same inconsistencies on his end.

The Podman documentation mentions Both user and group may be symbolic or numeric. for the --user option. This is also true for Docker where the documentation states Username or UID (format: <name|uid>[:<group|gid>]). Symbolic names don't actually work for either Podman or Docker so there's bug for bug consistency there.

What is different though is how /etc/{passwd,group} entries are handled. Docker doesn't add entries at all and just sets the specified UID and GID. Meanwhile, Podman adds the specified UID to /etc/passwd with the same username as on the host but the group name of the entry created in /etc/group uses the GID itself rather than the group name on the host.

I don't think there's any reason for passwd and group entries to not be created inside the container based on the entries from the host if they don't already exist in the image. I don't see any scenario where a user must have a certain UID and GID but must not have a passwd and group entry. If the same UID and GID exist in both the host and the image, it's probably best to not alter /etc/{passwd,group}.

Alternatively, the new --passwd-entry and --group-entry options can be used to add the entries independent of --user but the problem of what to do if there's a collision with a UID and GID that already exists in the image remains.

As for symbolic names, the only reason I can see to retain the bug is if something out there relies on it to fail which seems a bit far-fetched.

The following script illustrates the behavior of the different combinations of the parameters of the --user option when executed. Use sudo to enable execution of the docker commands so that SUDO_UID and SUDO_GID are set.

#!/bin/bash

# Both Docker and Podman document accepting either
# numeric or symbolic parameters for `--user`.

USER_ID="${SUDO_UID:-$(id --user)}"
GROUP_ID="${SUDO_GID:-$(id --group)}"
USER_NAME="$(id --user --name ${USER_ID})"
GROUP_NAME="$(id --group --name ${GROUP_ID})"

IMAGE="${IMAGE:-docker.io/library/alpine:latest}"

COMMANDS="
    id;
    getent passwd ${USER_ID} || echo 'Passwd entry not found.';
    getent group ${GROUP_ID} || echo 'Group entry not found.';
"

function docker_user() {
    echo
    echo "# Docker: sets just the UID but doesn't create a passwd entry."
    docker run --rm --user "${USER_ID}" "${IMAGE}" sh -c "${COMMANDS}"
    echo
    echo "# Docker: sets the UID and GID but doesn't create a passwd and group entry."
    docker run --rm --user "${USER_ID}:${GROUP_ID}" "${IMAGE}" sh -c "${COMMANDS}"
    echo
    echo "# Docker: symbolic user names don't work contrary to documentation."
    docker run --rm --user "${USER_NAME}" "${IMAGE}" sh -c "${COMMANDS}"
    echo
    echo "# Docker: a combination of the UID and the group name doesn't work either."
    docker run --rm --user "${USER_ID}:${GROUP_NAME}" "${IMAGE}" sh -c "${COMMANDS}"
}

function podman_user() {
    echo
    echo "# Podman: sets only the UID and creates a passwd entry with the correct"
    echo "# username but uses the GID as the name for the group entry."
    podman run --rm --user "${USER_ID}" "${IMAGE}" sh -c "${COMMANDS}"
    echo
    echo "# Podman: sets both the UID and GID as well as creating a passwd entry with"
    echo "# the correct username but uses the GID as the name for the group entry."
    podman run --rm --user "${USER_ID}:${GROUP_ID}" "${IMAGE}" sh -c "${COMMANDS}"
    echo
    echo "# Podman: as with Docker, symbolic user names don't work."
    podman run --rm --user "${USER_NAME}" "${IMAGE}" sh -c "${COMMANDS}"
    echo
    echo "# Podman: as with Docker, a combination of the UID and the group name doesn't work."
    podman run --rm --user "${USER_ID}:${GROUP_NAME}" "${IMAGE}" sh -c "${COMMANDS}"
}

echo "USER_ID:USER_NAME = ${USER_ID}:${USER_NAME}"
echo "GROUP_ID:GROUP_NAME = ${GROUP_ID}:${GROUP_NAME}"

[[ $EUID -eq 0 ]] && docker_user
podman_user

Steps to reproduce the issue

Steps to reproduce the issue

  1. Run the script above to illustrate the behavior of the different combinations of the parameters for the --user option.

Describe the results you received

On my system, the script outputs the following:

USER_ID:USER_NAME = 1000:core
GROUP_ID:GROUP_NAME = 1000:core

# Docker: sets just the UID but doesn't create a passwd entry.
uid=1000 gid=0(root) groups=0(root)
Passwd entry not found.
Group entry not found.

# Docker: sets the UID and GID but doesn't create a passwd and group entry.
uid=1000 gid=1000 groups=1000
Passwd entry not found.
Group entry not found.

# Docker: symbolic user names don't work contrary to documentation.
docker: Error response from daemon: unable to find user core: no matching entries in passwd file.

# Docker: a combination of the UID and the group name doesn't work either.
docker: Error response from daemon: unable to find group core: no matching entries in group file.

# Podman: sets only the UID and creates a passwd entry with the correct
# username but uses the GID as the name for the group entry.
uid=1000(core) gid=0(root) groups=0(root)
core:*:1000:0:CoreOS Admin:/:/bin/sh
1000:x:1000:1000

# Podman: sets both the UID and GID as well as creating a passwd entry with
# the correct username but uses the GID as the name for the group entry.
uid=1000(core) gid=1000(1000) groups=1000(1000)
core:*:1000:1000:CoreOS Admin:/:/bin/sh
1000:x:1000:1000

# Podman: as with Docker, symbolic user names don't work.
Error: unable to find user core: no matching entries in passwd file

# Podman: as with Docker, a combination of the UID and the group name doesn't work.
Error: unable to find group core: no matching entries in group file

Describe the results you expected

Ideally, --user should just add passwd and group entries with the names from the host to the container if they don't already exist, whether specified numerically or symbolically.

podman info output

version:
  APIVersion: 4.5.0
  Built: 1681486942
  BuiltTime: Fri Apr 14 15:42:22 2023
  GitCommit: ""
  GoVersion: go1.20.2
  Os: linux
  OsArch: linux/amd64
  Version: 4.5.0

Podman in a container

No

Privileged Or Rootless

None

Upstream Latest Release

Yes

Additional information

Updated the script to use a combination of the UID and the group name since it's pointless to test a combination of the user and group names when it already fails on just the user name.

@cevich
Copy link
Member

cevich commented Jun 15, 2023

I'm thinking maybe this should be an RFE. But I'll let others comment.

See also the slightly related: #18902

@Luap99
Copy link
Member

Luap99 commented Jun 16, 2023

Note if you specify a name with --user the names are looked up in the images /etc/{passwd,group} not the one from the host.

If you want to add host users there is --hostuser

@cevich
Copy link
Member

cevich commented Jun 16, 2023

Cross-posting my comment from #18902:

Perhaps we should bring the `--group-entry` and `--user` oddities to a community
cabal and see if we can arrive at a better direction to take them, maybe for
5.0?

Though after reading Paul's comment above, I'd consider just including all the related options as well. Basically all options that let the user control UID/GID in the container at runtime, along with manipulating /etc/passwd and /etc/group.

@justinjereza
Copy link
Author

Note if you specify a name with --user the names are looked up in the images /etc/{passwd,group} not the one from the host.

If you want to add host users there is --hostuser

Yes except --user adds the passwd entry that doesn't exist in the image. What I'm thinking is either --user shouldn't add passwd and group entries at all and the addition of entries in the container should be done via --hostuser, --passwd-entry, --group-entry, etc. or --user should add proper passwd and group entries from the host if specified. The former would be closer to Docker behavior if that is what's desired. The current situation we have with --user is one where the passwd entry from the host is added and the group entry is sorta added with a name that can be confusing.

Perhaps we should bring the `--group-entry` and `--user` oddities to a community
cabal and see if we can arrive at a better direction to take them, maybe for
5.0?

Though after reading Paul's comment above, I'd consider just including all the related options as well. Basically all options that let the user control UID/GID in the container at runtime, along with manipulating /etc/passwd and /etc/group.

I think this makes sense so usage patterns for all those options can be mapped out with definitely known and consistent effects.

@justinjereza
Copy link
Author

justinjereza commented Jun 16, 2023

For the case where --user just adds entries to the container, I envisage it to be something like this:

if user specified AND passwd_entry_id exists in host AND no passwd_entry_id exists in image:
    copy passwd entry name, uid, and gecos from host to container

if group specified AND group_entry_id exists in host AND no group_entry_id exists in image:
    copy group entry name and gid from host to container
    if user specified:
        set passwd_entry_id's gid to group_entry_id

Podman won't overwrite entries with a UID and GID that already exist in an image. If the specified user/group doesn't exist on the host, do it just like Docker would setting UID/GID without adding an entry.

EDIT: Added user specified condition to passwd entry handling to account for the fact that --user :$GID can be specified resulting in uid=0(root) gid=2000(2000) groups=2000(2000) inside a container.

@cevich
Copy link
Member

cevich commented Jun 16, 2023

the addition of entries in the container should be done via --hostuser, --passwd-entry, --group-entry, etc.

Consistency with Docker is important. I agree, I think this idea (moving --user <UID>:<GID> functionality to other options) provides a better user experience (one feature per option). It's also easier to document and cleaner to test that way. Since Docker doesn't have --hostuser/--passwd-entry/--group-entry, we're more "free" to innovate there than trying to overload --user.

(It might make sense to add a --hostgroup option as well.)

For the case where --user just adds entries to the container, I envisage it to be something like

Yeah, @Luap99 that seems to be a good way to fixup --user for now.

I'm slightly annoyed we've packed multiple features into the --user option, while having other options that overlap in part (--group-entry) or whole (--hostuser). This can be really confusing for users, hard to document, ugly to test, and more fragile overall. Maybe for Podman 5, this egg can be unscrambled...

I think this makes sense so usage patterns for all those options can be mapped out with definitely known and consistent effects.

Yeah, the current situation seems to be needlessly messy.

It looks like the next community cabal meeting will be on Jul. 20th @ 11am EST. Unfortunately I'm going to be out on PTO that week. The following one is scheduled for Aug. 17th. @justinjereza would you be willing to attend and drive this RFE on the 20th? Otherwise I'm happy to take it up in August. Podman 5 seems pretty far off, though it would be good to lay down some plans.

(cc: @TomSweeneyRedHat)

@justinjereza
Copy link
Author

@justinjereza would you be willing to attend and drive this RFE on the 20th?

@cevich I can tentatively commit to July 20, 11am EST. It's a bit far off so my schedule might change. I'll let you guys know if that happens. For now, I'll add this to the agenda.

@github-actions
Copy link

A friendly reminder that this issue had no activity for 30 days.

@mheon
Copy link
Member

mheon commented Jul 20, 2023

@rhatdan If I recall correctly, you were the a strong proponent behind the original changes to --user and --group that made them modify passwd/group - any thoughts on this issue?

@justinjereza
Copy link
Author

Validating all the different ways that can cause a passwd/group entry to be unexpectedly added or not added is taking me more time than I thought. When I'm done writing everything that I wasn't able to express clearly during the meeting, should I just post it here or would moving it to a discussion be preferable?

@rhatdan
Copy link
Member

rhatdan commented Jul 20, 2023

The idea was to allow getpwuser to return useful information and not fail.
For the most part this is probably a documentation issue. Of course Docker does not really support rootless user to the same amount as Podman, for example no support for --userns=keepid.

@justinjereza
Copy link
Author

@cevich @mheon @Luap99 @rhatdan @TomSweeneyRedHat

Podman Cabal Meeting (July 20, 2023)

This is my perspective of what was discussed regarding this issue and isn't an exact record. My hope is to clarify what I feel like I wasn't able express clearly as well as to integrate comments that were made. In hindsight, this topic seems bigger than I expected and there are a lot of things that I failed to consider preceeding the meeting.

I have observed the following behavior on Fedora CoreOS with Podman 4.5.1 and the only user on the system is the default core passwd and group entries.

Passwd and Group Entry Handling

TL;DR

  • --user USER - Maybe this shouldn't add a group entry that wasn't specified since the user doesn't use the group anyway?
  • --user :GROUP - If the group exists on the host, maybe the group name should be copied from the host?
  • --user USER:GROUP - Same as above.
  • --passwd-entry ENTRY - The passwd entry is only added depending on the UID provided with --user. Maybe this should just add a passwd entry regardless of other options?
  • --group-entry ENTRY - The group entry is only added depending on either the UID provided with --user or if the GID is used by --user. Maybe this should just add a group entry regardless of other options?
  • --hostuser - This works as expected.
  • --hostgroup - Doesn't exist but maybe it can be added as a counterpart to --hostuser?

There are four options that may modify the passwd/group entries of a container:

  • --user
  • --passwd-entry
  • --group-entry
  • --hostuser

Of these, only --user exists in Docker. The rest are additions by Podman.

A concern is that the final state of the container can become difficult to predict with the different combinations of these options. Their effect on a container can overlap and which option takes precedence is undocumented. I am not sure that I've discovered all the different ways that passwd and/or group entry creation may be contrary to what I expected.

It was mentioned that removing an option in an effort to streamline passwd/group entry handling is not an option. After reviewing as much as I could while writing this, all the different existing options seem different enough that it doesn't seem necessary to remove any option.

Instead, I have attempted to enumerate the different behaviors of each of the options given different variables and hopefully, ideas on how we can define expected behavior for each of them.

--user USER[:GROUP]

There are a three ways to specify this option as mentioned below.

--user USER

Podman adds a passwd entry for the specified user if it does not already exist in the image. The user may be specified by UID or name.

Assuming the user does not exist in the image:

  • If the user is specified by UID and exists on the host, the passwd entry copies the name, UID, and GECOS fields from the host.
$ podman run --rm --user '1000' fedora:latest sh -c 'id; getent passwd 1000; getent group 1000;'
uid=1000(core) gid=0(root) groups=0(root)
core:*:1000:0:CoreOS Admin:/:/bin/sh
1000:x:1000:1000
  • If the user is specified by UID and doesn't exist on the host, a passwd entry is added with the UID as the name, the UID, and GECOS is "container user".
$ podman run --rm --user '1001' fedora:latest sh -c 'id; getent passwd 1001; getent group 1001;'
uid=1001(1001) gid=0(root) groups=0(root)
1001:*:1001:0:container user:/:/bin/sh
1001:x:1001:1001

In both of these cases a group entry is created where the UID is used as the GID and following the behavior of --user :GROUP. Is it correct to create a group that wasn't specifically requested?

  • If the user is specified by name, Podman exits with an error.
$ podman run --rm --user 'core' fedora:latest
Error: unable to find user core: no matching entries in passwd file

While Podman adds a passwd and group entry, Docker does not. It was mentioned in the meeting that this deviation is necessary to support toolbox where you definitely want to have a passwd entry for the user on the host. The --userns keep-id option is similar in that you also want to have a passwd entry similar to toolbox. Given that, it was mentioned that the deviation from Docker behavior is necessary and the behavior above is as I'd expect given that necessity.

--user :GROUP

I mistakenly called this the --group option.

Podman adds the specified group entry if it does not already exist in the image. The group may be specified by GID or name.

Assuming the group does not exist in the image:

If the group is specified by GID, a group entry is added with the GID as the name regardless of whether it exists on the host or not. Since the behavior is unlike what is done for a user, it was mentioned that it looks like a bug and it would be ideal to copy the name from the host if possible. It can cause confusion when you expect a name and instead see a GID in something like file listings.

$ # GID 1000 exists on the host
$ podman run --rm --user ':1000' fedora:latest sh -c 'id; getent group 1000;'
uid=0(root) gid=1000(1000) groups=1000(1000)
1000:x:1000:
$ # GID 1001 does not exist on the host
$ podman run --rm --user ':1001' fedora:latest sh -c 'id; getent group 1001;'
uid=0(root) gid=1001(1001) groups=1001(1001)
1001:x:1001:

If the group is specified by name, Podman exits with an error.

$ podman run --rm --user ':core' fedora:latest
Error: unable to find group core: no matching entries in group file

--user USER:GROUP

This adds a passwd and group entry in the manner mentioned above.

--passwd-entry ENTRY

This adds an arbitrary passwd entry to the container only if there's a --user option that specifies a UID that does not exist in the image.

Examples:

UID 1 is bin, passwd entry is not added.

$ podman run --rm --passwd-entry 'foo:x:1000:1000:myuser:/:/bin/sh' --user 1 fedora:latest sh -c 'id; getent passwd 1000; getent group 1000;'
uid=1(bin) gid=1(bin) groups=1(bin)

UID 9 doesn't exist, passwd entry is added.

$ podman run --rm --passwd-entry 'foo:x:1000:1000:myuser:/:/bin/sh' --user 9 fedora:latest sh -c 'id; getent passwd 1000; getent group 1000;'
uid=9 gid=0(root) groups=0(root)
foo:x:1000:1000:myuser:/:/bin/sh

Is it a good idea to change this behavior so that it will add and even modify passwd entries regardless of whether --user is specified? This will allow this option to be specified multiple times to add or modify multiple passwd entries.

--group-entry ENTRY

This adds an arbitrary group entry to the container only if there's a --user option that specifies a UID that does not exist in the image.

Depending on the distro of the image, the UID specified must also not be below a certain UID. On Fedora, it seems the UID must at least be above 10. On Alpine, the group entry is only added with a UID above 300. This seems to be beyond the control of Podman and therefore not relevant.

Examples:

On Fedora with UID 10, entry is not added.

$ podman run --rm --group-entry 'foo:x:1000:' --user 10 fedora:latest sh -c 'id; getent passwd 10; getent group 1000;'
uid=10(10) gid=0(root) groups=0(root)
10:*:10:0:container user:/:/bin/sh

On Fedora with UID 13, entry is added.

$ podman run --rm --group-entry 'foo:x:1000:' --user 13 fedora:latest sh -c 'id; getent passwd 13; getent group 1000;'
uid=13(13) gid=0(root) groups=0(root)
13:*:13:0:container user:/:/bin/sh
foo:x:1000:

On Alpine with UID 300, entry is not added.

$ podman run --rm --group-entry 'foo:x:1000:' --user 300 alpine:latest sh -c 'id; getent passwd 300; getent group 1000;'
uid=300(300) gid=0(root) groups=0(root)
300:*:300:0:container user:/:/bin/sh

On Alpine with UID 301, entry is added.

$ podman run --rm --group-entry 'foo:x:1000:' --user 301 alpine:latest sh -c 'id; getent passwd 301; getent group 1000;'
uid=301(301) gid=0(root) groups=0(root)
301:*:301:0:container user:/:/bin/sh
foo:x:1000

The group entry is also added regardless of the UID for as long as the GID is used by --user.

$ podman run --rm --group-entry 'foo:x:1000:' --user :1000 fedora:latest sh -c 'id; getent passwd 0; getent group 1000;'
uid=0(root) gid=1000(foo) groups=1000(foo)
root:x:0:0:Super User:/root:/bin/bash
foo:x:1000:

Similar to --passwd-entry, maybe it'd be better to just add the group entry regardless of other factors and allow multiple specification of the option?

--hostuser NAME

This adds a passwd entry that exists on the host.

I was mistaken in thinking this can be thought of as a convenience function for --passwd-entry "$(getent passwd $NAME)", provided that $NAME exists.

The difference is --passwd-entry adds an entry verbatim while --hostuser copies the host passwd entry in a manner similar to --user, regardless of whether --user is specified or not.

This seems to work as expected.

--hostgroup NAME

This option doesn't exist but if it is written, it can conceivably function the same as --hostuser but for groups.

@cevich
Copy link
Member

cevich commented Jul 25, 2023

Thanks for driving this @justinjereza and for the excellent summary. I skimmed (quickly) the tl;dr section, and it seems there are at least three categories of actions that can be taken:

  1. Broken/wrong/confusing CLI Options which can safely be fixed in 4.x.y w/o breaking anybody (also) dependent on current behaviors.
  2. Minor features which can safely go into a 4.x.
  3. Major rewrite/features which can only go into a 5.x

IMHO, items in 1. and 2. should have individual issues opened up. For 3., I think a discussion topic would be a good place.

@github-actions
Copy link

A friendly reminder that this issue had no activity for 30 days.

@rhatdan
Copy link
Member

rhatdan commented Aug 26, 2023

@justinjereza Are you still working on this?

@p0da
Copy link

p0da commented Dec 19, 2023

Having not seen this issue I previously filed #20002, points:

--passwd-entry ENTRY - The passwd entry is only added depending on the UID provided with --user. Maybe this should just add a passwd entry regardless of other options?
--group-entry ENTRY - The group entry is only added depending on either the UID provided with --user or if the GID is used by --user. Maybe this should just add a group entry regardless of other options?

address that issue.

@rhatdan for the time being can the --*-entry flags be modified to function independent of other options?

@rhatdan
Copy link
Member

rhatdan commented Dec 21, 2023

I would be fine with making them independent.

@rhatdan
Copy link
Member

rhatdan commented Dec 21, 2023

Interested in opening a PR?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/bug Categorizes issue or PR as related to a bug.
Projects
None yet
Development

No branches or pull requests

6 participants