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

podman: add uid and gid options to keep-id #15389

Merged
merged 3 commits into from
Aug 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions docs/source/markdown/options/userns.container.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#### **--userns**=*mode*

Set the user namespace mode for the container. It defaults to the **PODMAN_USERNS** environment variable. An empty value ("") means user namespaces are disabled unless an explicit mapping is set with the **--uidmap** and **--gidmap** options.

This option is incompatible with **--gidmap**, **--uidmap**, **--subuidname** and **--subgidname**.

Rootless user --userns=Key mappings:

Key | Host User | Container User
----------|---------------|---------------------
"" |$UID |0 (Default User account mapped to root user in container.)
keep-id |$UID |$UID (Map user account to same UID within container.)
auto |$UID | nil (Host User UID is not mapped into container.)
nomap |$UID | nil (Host User UID is not mapped into container.)

Valid _mode_ values are:

**auto**[:_OPTIONS,..._]: automatically create a unique user namespace.

The `--userns=auto` flag, requires that the user name `containers` and a range of subordinate user ids that the Podman container is allowed to use be specified in the /etc/subuid and /etc/subgid files.

Example: `containers:2147483647:2147483648`.

Podman allocates unique ranges of UIDs and GIDs from the `containers` subordinate user ids. The size of the ranges is based on the number of UIDs required in the image. The number of UIDs and GIDs can be overridden with the `size` option.

The rootless option `--userns=keep-id` uses all the subuids and subgids of the user. Using `--userns=auto` when starting new containers will not work as long as any containers exist that were started with `--userns=keep-id`.

Valid `auto` options:

- *gidmapping*=_CONTAINER_GID:HOST_GID:SIZE_: to force a GID mapping to be present in the user namespace.
- *size*=_SIZE_: to specify an explicit size for the automatic user namespace. e.g. `--userns=auto:size=8192`. If `size` is not specified, `auto` will estimate a size for the user namespace.
- *uidmapping*=_CONTAINER_UID:HOST_UID:SIZE_: to force a UID mapping to be present in the user namespace.

**container:**_id_: join the user namespace of the specified container.

**host**: run in the user namespace of the caller. The processes running in the container will have the same privileges on the host as any other process launched by the calling user (default).

**keep-id**: creates a user namespace where the current rootless user's UID:GID are mapped to the same values in the container. This option is not allowed for containers created by the root user.

Valid `keep-id` options:

- *uid*=UID: override the UID inside the container that will be used to map the current rootless user to.
- *gid*=GID: override the GID inside the container that will be used to map the current rootless user to.

**nomap**: creates a user namespace where the current rootless user's UID:GID are not mapped into the container. This option is not allowed for containers created by the root user.

**ns:**_namespace_: run the <<container|pod>> in the given existing user namespace.
43 changes: 1 addition & 42 deletions docs/source/markdown/podman-create.1.md.in
Original file line number Diff line number Diff line change
Expand Up @@ -652,48 +652,7 @@ The following examples are all valid:

Without this argument the command will be run as root in the container.

#### **--userns**=*mode*

Set the user namespace mode for the container. It defaults to the **PODMAN_USERNS** environment variable. An empty value ("") means user namespaces are disabled unless an explicit mapping is set with the **--uidmap** and **--gidmap** options.

Rootless user --userns=Key mappings:

Key | Host User | Container User
----------|---------------|---------------------
"" |$UID |0 (Default User account mapped to root user in container.)
keep-id |$UID |$UID (Map user account to same UID within container.)
auto |$UID | nil (Host User UID is not mapped into container.)
nomap |$UID | nil (Host User UID is not mapped into container.)

Valid _mode_ values are:

**auto**[:_OPTIONS,..._]: automatically create a unique user namespace.

The `--userns=auto` flag, requires that the user name `containers` and a range of subordinate user ids that the Podman container is allowed to use be specified in the /etc/subuid and /etc/subgid files.

Example: `containers:2147483647:2147483648`.

Podman allocates unique ranges of UIDs and GIDs from the `containers` subordinate user ids. The size of the ranges is based on the number of UIDs required in the image. The number of UIDs and GIDs can be overridden with the `size` option. The `auto` options currently does not work in rootless mode

Valid `auto` options:

- *gidmapping*=_CONTAINER_GID:HOST_GID:SIZE_: to force a GID mapping to be present in the user namespace.
- *size*=_SIZE_: to specify an explicit size for the automatic user namespace. e.g. `--userns=auto:size=8192`. If `size` is not specified, `auto` will estimate a size for the user namespace.
- *uidmapping*=_CONTAINER_UID:HOST_UID:SIZE_: to force a UID mapping to be present in the user namespace.

**container:**_id_: join the user namespace of the specified container.

**host**: run in the user namespace of the caller. The processes running in the container will have the same privileges on the host as any other process launched by the calling user (default).

**keep-id**: creates a user namespace where the current rootless user's UID:GID are mapped to the same values in the container. This option is not allowed for containers created by the root user.

**nomap**: creates a user namespace where the current rootless user's UID:GID are not mapped into the container. This option is not allowed for containers created by the root user.

**ns:**_namespace_: run the container in the given existing user namespace.

**private**: create a new namespace for the container.

This option is incompatible with **--gidmap**, **--uidmap**, **--subuidname** and **--subgidname**.
@@option userns.container

@@option uts.container

Expand Down
40 changes: 1 addition & 39 deletions docs/source/markdown/podman-kube-play.1.md.in
Original file line number Diff line number Diff line change
Expand Up @@ -225,45 +225,7 @@ Require HTTPS and verify certificates when contacting registries (default: true)
then TLS verification will be used. If set to false, then TLS verification will not be used. If not specified,
TLS verification will be used unless the target registry is listed as an insecure registry in registries.conf.

#### **--userns**=*mode*

Set the user namespace mode for the container. It defaults to the **PODMAN_USERNS** environment variable. An empty value ("") means user namespaces are disabled unless an explicit mapping is set with the **--uidmap** and **--gidmap** options.

Rootless user --userns=Key mappings:

Key | Host User | Container User
----------|---------------|---------------------
"" |$UID |0 (Default User account mapped to root user in container.)
keep-id |$UID |$UID (Map user account to same UID within container.)
auto |$UID | nil (Host User UID is not mapped into container.)
nomap |$UID | nil (Host User UID is not mapped into container.)

Valid _mode_ values are:

**auto**[:_OPTIONS,..._]: automatically create a unique user namespace.

The `--userns=auto` flag, requires that the user name `containers` and a range of subordinate user ids that the Podman container is allowed to use be specified in the /etc/subuid and /etc/subgid files.

Example: `containers:2147483647:2147483648`.

Podman allocates unique ranges of UIDs and GIDs from the `containers` subordinate user ids. The size of the ranges is based on the number of UIDs required in the image. The number of UIDs and GIDs can be overridden with the `size` option. The `auto` options currently does not work in rootless mode

Valid `auto` options:

- *gidmapping*=_CONTAINER_GID:HOST_GID:SIZE_: to force a GID mapping to be present in the user namespace.
- *size*=_SIZE_: to specify an explicit size for the automatic user namespace. e.g. `--userns=auto:size=8192`. If `size` is not specified, `auto` will estimate a size for the user namespace.
- *uidmapping*=_CONTAINER_UID:HOST_UID:SIZE_: to force a UID mapping to be present in the user namespace.

**container:**_id_: join the user namespace of the specified container.

**host**: create a new namespace for the container.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This text loses out. Someone please double-check that the new text is applicable to kube-play.


**keep-id**: creates a user namespace where the current rootless user's UID:GID are mapped to the same values in the container. This option is not allowed for containers created by the root user.

**nomap**: creates a user namespace where the current rootless user's UID:GID are not mapped into the container. This option is not allowed for containers created by the root user.

**ns:**_namespace_: run the pod in the given existing user namespace.

@@option userns.container
## EXAMPLES

Recreate the pod and containers as described in a file called `demo.yml`
Expand Down
44 changes: 1 addition & 43 deletions docs/source/markdown/podman-run.1.md.in
Original file line number Diff line number Diff line change
Expand Up @@ -708,49 +708,7 @@ Without this argument, the command will run as the user specified in the contain

When a user namespace is not in use, the UID and GID used within the container and on the host will match. When user namespaces are in use, however, the UID and GID in the container may correspond to another UID and GID on the host. In rootless containers, for example, a user namespace is always used, and root in the container will by default correspond to the UID and GID of the user invoking Podman.

#### **--userns**=*mode*

Set the user namespace mode for the container. It defaults to the **PODMAN_USERNS** environment variable. An empty value ("") means user namespaces are disabled unless an explicit mapping is set with the **--uidmap** and **--gidmap** options.

Rootless user --userns=Key mappings:

Key | Host User | Container User
----------|---------------|---------------------
"" |$UID |0 (Default User account mapped to root user in container.)
keep-id |$UID |$UID (Map user account to same UID within container.)
auto |$UID | nil (Host User UID is not mapped into container.)
nomap |$UID | nil (Host User UID is not mapped into container.)

Valid _mode_ values are:

**auto**[:_OPTIONS,..._]: automatically create a unique user namespace.

The `--userns=auto` flag, requires that the user name `containers` and a range of subordinate user ids that the Podman container is allowed to use be specified in the /etc/subuid and /etc/subgid files.

Example: `containers:2147483647:2147483648`.

Podman allocates unique ranges of UIDs and GIDs from the `containers` subordinate user ids. The size of the ranges is based on the number of UIDs required in the image. The number of UIDs and GIDs can be overridden with the `size` option.

The rootless option `--userns=keep-id` uses all the subuids and subgids of the user. Using `--userns=auto` when starting new containers will not work as long as any containers exist that were started with `--userns=keep-id`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line does not appear in any other file (podman-create, podman-kube-play) and was not selected for the final winner.


Valid `auto` options:

- *gidmapping*=_CONTAINER_GID:HOST_GID:SIZE_: to force a GID mapping to be present in the user namespace.
- *size*=_SIZE_: to specify an explicit size for the automatic user namespace. e.g. `--userns=auto:size=8192`. If `size` is not specified, `auto` will estimate a size for the user namespace.
- *uidmapping*=_CONTAINER_UID:HOST_UID:SIZE_: to force a UID mapping to be present in the user namespace.

**container:**_id_: join the user namespace of the specified container.

**host**: run in the user namespace of the caller. The processes running in the container will have the same privileges on the host as any other process launched by the calling user (default).

**keep-id**: creates a user namespace where the current rootless user's UID:GID are mapped to the same values in the container. This option is not allowed for containers created by the root user.

**nomap**: creates a user namespace where the current rootless user's UID:GID are not mapped into the container. This option is not allowed for containers created by the root user.

**ns:**_namespace_: run the container in the given existing user namespace.

**private**: create a new namespace for the container.
This option is incompatible with **--gidmap**, **--uidmap**, **--subuidname** and **--subgidname**.
@@option userns.container

@@option uts.container

Expand Down
51 changes: 0 additions & 51 deletions pkg/domain/infra/runtime_libpod.go
Original file line number Diff line number Diff line change
Expand Up @@ -294,57 +294,6 @@ func ParseIDMapping(mode namespaces.UsernsMode, uidMapSlice, gidMapSlice []strin
options.AutoUserNsOpts = *opts
return &options, nil
}
if mode.IsKeepID() {
if len(uidMapSlice) > 0 || len(gidMapSlice) > 0 {
return nil, errors.New("cannot specify custom mappings with --userns=keep-id")
}
if len(subUIDMap) > 0 || len(subGIDMap) > 0 {
return nil, errors.New("cannot specify subuidmap or subgidmap with --userns=keep-id")
}
if !rootless.IsRootless() {
return nil, errors.New("keep-id is only supported in rootless mode")
}
min := func(a, b int) int {
if a < b {
return a
}
return b
}

uid := rootless.GetRootlessUID()
gid := rootless.GetRootlessGID()

uids, gids, err := rootless.GetConfiguredMappings()
if err != nil {
return nil, fmt.Errorf("cannot read mappings: %w", err)
}
maxUID, maxGID := 0, 0
for _, u := range uids {
maxUID += u.Size
}
for _, g := range gids {
maxGID += g.Size
}

options.UIDMap, options.GIDMap = nil, nil

options.UIDMap = append(options.UIDMap, idtools.IDMap{ContainerID: 0, HostID: 1, Size: min(uid, maxUID)})
options.UIDMap = append(options.UIDMap, idtools.IDMap{ContainerID: uid, HostID: 0, Size: 1})
if maxUID > uid {
options.UIDMap = append(options.UIDMap, idtools.IDMap{ContainerID: uid + 1, HostID: uid + 1, Size: maxUID - uid})
}

options.GIDMap = append(options.GIDMap, idtools.IDMap{ContainerID: 0, HostID: 1, Size: min(gid, maxGID)})
options.GIDMap = append(options.GIDMap, idtools.IDMap{ContainerID: gid, HostID: 0, Size: 1})
if maxGID > gid {
options.GIDMap = append(options.GIDMap, idtools.IDMap{ContainerID: gid + 1, HostID: gid + 1, Size: maxGID - gid})
}

options.HostUIDMapping = false
options.HostGIDMapping = false
// Simply ignore the setting and do not set up an inner namespace for root as it is a no-op
return &options, nil
}

if subGIDMap == "" && subUIDMap != "" {
subGIDMap = subUIDMap
Expand Down
49 changes: 48 additions & 1 deletion pkg/namespaces/namespaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@ const (
slirpType = "slirp4netns"
)

// KeepIDUserNsOptions defines how to keepIDmatically create a user namespace.
type KeepIDUserNsOptions struct {
// UID is the target uid in the user namespace.
UID *uint32
// GID is the target uid in the user namespace.
GID *uint32
}

// CgroupMode represents cgroup mode in the container.
type CgroupMode string

Expand Down Expand Up @@ -93,7 +101,8 @@ func (n UsernsMode) IsHost() bool {

// IsKeepID indicates whether container uses a mapping where the (uid, gid) on the host is kept inside of the namespace.
func (n UsernsMode) IsKeepID() bool {
return n == "keep-id"
parts := strings.Split(string(n), ":")
return parts[0] == "keep-id"
}

// IsNoMap indicates whether container uses a mapping where the (uid, gid) on the host is not present in the namespace.
Expand Down Expand Up @@ -154,6 +163,44 @@ func (n UsernsMode) GetAutoOptions() (*types.AutoUserNsOptions, error) {
return &options, nil
}

// GetKeepIDOptions returns a KeepIDUserNsOptions with the settings to keepIDmatically set up
// a user namespace.
func (n UsernsMode) GetKeepIDOptions() (*KeepIDUserNsOptions, error) {
parts := strings.SplitN(string(n), ":", 2)
if parts[0] != "keep-id" {
return nil, fmt.Errorf("wrong user namespace mode")
}
options := KeepIDUserNsOptions{}
if len(parts) == 1 {
return &options, nil
}
for _, o := range strings.Split(parts[1], ",") {
v := strings.SplitN(o, "=", 2)
if len(v) != 2 {
return nil, fmt.Errorf("invalid option specified: %q", o)
}
switch v[0] {
case "uid":
s, err := strconv.ParseUint(v[1], 10, 32)
if err != nil {
return nil, err
}
v := uint32(s)
options.UID = &v
case "gid":
s, err := strconv.ParseUint(v[1], 10, 32)
if err != nil {
return nil, err
}
v := uint32(s)
options.GID = &v
default:
return nil, fmt.Errorf("unknown option specified: %q", v[0])
}
}
return &options, nil
}

// IsPrivate indicates whether the container uses the a private userns.
func (n UsernsMode) IsPrivate() bool {
return !(n.IsHost() || n.IsContainer())
Expand Down
11 changes: 9 additions & 2 deletions pkg/specgen/generate/namespaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/containers/common/pkg/config"
"github.com/containers/podman/v4/libpod"
"github.com/containers/podman/v4/libpod/define"
"github.com/containers/podman/v4/pkg/namespaces"
"github.com/containers/podman/v4/pkg/rootless"
"github.com/containers/podman/v4/pkg/specgen"
"github.com/containers/podman/v4/pkg/util"
Expand Down Expand Up @@ -198,12 +199,18 @@ func namespaceOptions(s *specgen.SpecGenerator, rt *libpod.Runtime, pod *libpod.
if !rootless.IsRootless() {
return nil, errors.New("keep-id is only supported in rootless mode")
}
toReturn = append(toReturn, libpod.WithAddCurrentUserPasswdEntry())
opts, err := namespaces.UsernsMode(s.UserNS.String()).GetKeepIDOptions()
if err != nil {
return nil, err
}
if opts.UID == nil && opts.GID == nil {
toReturn = append(toReturn, libpod.WithAddCurrentUserPasswdEntry())
}

// If user is not overridden, set user in the container
// to user running Podman.
if s.User == "" {
_, uid, gid, err := util.GetKeepIDMapping()
_, uid, gid, err := util.GetKeepIDMapping(opts)
if err != nil {
return nil, err
}
Expand Down
15 changes: 14 additions & 1 deletion pkg/specgen/namespaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/containers/common/pkg/cgroups"
cutil "github.com/containers/common/pkg/util"
"github.com/containers/podman/v4/libpod/define"
"github.com/containers/podman/v4/pkg/namespaces"
"github.com/containers/podman/v4/pkg/util"
"github.com/containers/storage"
spec "github.com/opencontainers/runtime-spec/specs-go"
Expand Down Expand Up @@ -308,6 +309,14 @@ func ParseUserNamespace(ns string) (Namespace, error) {
case ns == "keep-id":
toReturn.NSMode = KeepID
return toReturn, nil
case strings.HasPrefix(ns, "keep-id:"):
split := strings.SplitN(ns, ":", 2)
if len(split) != 2 {
return toReturn, errors.New("invalid setting for keep-id: mode")
}
toReturn.NSMode = KeepID
toReturn.Value = split[1]
return toReturn, nil
case ns == "nomap":
toReturn.NSMode = NoMap
return toReturn, nil
Expand Down Expand Up @@ -490,7 +499,11 @@ func SetupUserNS(idmappings *storage.IDMappingOptions, userns Namespace, g *gene
return user, err
}
case KeepID:
mappings, uid, gid, err := util.GetKeepIDMapping()
opts, err := namespaces.UsernsMode(userns.String()).GetKeepIDOptions()
if err != nil {
return user, err
}
mappings, uid, gid, err := util.GetKeepIDMapping(opts)
if err != nil {
return user, err
}
Expand Down
Loading