mirror of
https://github.com/containers/podman.git
synced 2025-05-19 08:07:10 +08:00
userns: support --userns=auto
automatically pick an empty range and create an user namespace for the container. Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
This commit is contained in:
@ -823,6 +823,7 @@ The following examples are all valid:
|
|||||||
|
|
||||||
Without this argument the command will be run as root in the container.
|
Without this argument the command will be run as root in the container.
|
||||||
|
|
||||||
|
**--userns**=*auto*[:OPTIONS]
|
||||||
**--userns**=*host*
|
**--userns**=*host*
|
||||||
**--userns**=*keep-id*
|
**--userns**=*keep-id*
|
||||||
**--userns**=container:container
|
**--userns**=container:container
|
||||||
@ -831,6 +832,11 @@ Without this argument the command will be run as root in the container.
|
|||||||
|
|
||||||
Set the user namespace mode for the container. It defaults to the **PODMAN_USERNS** environment variable. An empty value means user namespaces are disabled.
|
Set the user namespace mode for the container. It defaults to the **PODMAN_USERNS** environment variable. An empty value means user namespaces are disabled.
|
||||||
|
|
||||||
|
|
||||||
|
- `auto`: automatically create a namespace. It is possible to specify other options to `auto`. The supported options are
|
||||||
|
**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 guess a size for the user namespace.
|
||||||
|
**uidmapping=HOST_UID:CONTAINER_UID:SIZE** to force a UID mapping to be present in the user namespace.
|
||||||
|
**gidmapping=HOST_UID:CONTAINER_UID:SIZE** to force a GID mapping to be present in the user namespace.
|
||||||
- `container`: join the user namespace of the specified container.
|
- `container`: join the user namespace of the specified container.
|
||||||
- `host`: run in the user namespace of the caller. This is the default if no user namespace options are set. The processes running in the container will have the same privileges on the host as any other process launched by the calling user.
|
- `host`: run in the user namespace of the caller. This is the default if no user namespace options are set. The processes running in the container will have the same privileges on the host as any other process launched by the calling user.
|
||||||
- `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 ignored for containers created by the root user.
|
- `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 ignored for containers created by the root user.
|
||||||
|
@ -862,10 +862,14 @@ Sets the username or UID used and optionally the groupname or GID for the specif
|
|||||||
|
|
||||||
Without this argument the command will be run as root in the container.
|
Without this argument the command will be run as root in the container.
|
||||||
|
|
||||||
**--userns**=**host**|**keep-id**|**container:**_id_|**ns:**_namespace_
|
**--userns**=**auto**|**host**|**keep-id**|**container:**_id_|**ns:**_namespace_
|
||||||
|
|
||||||
Set the user namespace mode for the container. It defaults to the **PODMAN_USERNS** environment variable. An empty value means user namespaces are disabled.
|
Set the user namespace mode for the container. It defaults to the **PODMAN_USERNS** environment variable. An empty value means user namespaces are disabled.
|
||||||
|
|
||||||
|
- **auto**: automatically create a namespace. It is possible to specify other options to `auto`. The supported options are
|
||||||
|
**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 guess a size for the user namespace.
|
||||||
|
**uidmapping=HOST_UID:CONTAINER_UID:SIZE** to force a UID mapping to be present in the user namespace.
|
||||||
|
**gidmapping=HOST_UID:CONTAINER_UID:SIZE** to force a GID mapping to be present in the user namespace.
|
||||||
- **host**: run in the user namespace of the caller. This is the default if no user namespace options are set. The processes running in the container will have the same privileges on the host as any other process launched by the calling user.
|
- **host**: run in the user namespace of the caller. This is the default if no user namespace options are set. The processes running in the container will have the same privileges on the host as any other process launched by the calling user.
|
||||||
- **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 ignored for containers created by the root user.
|
- **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 ignored for containers created by the root user.
|
||||||
- **ns**: run the container in the given existing user namespace.
|
- **ns**: run the container in the given existing user namespace.
|
||||||
|
@ -339,6 +339,29 @@ func (c *Container) syncContainer() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Container) setupStorageMapping(dest, from *storage.IDMappingOptions) {
|
||||||
|
if c.config.Rootfs != "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
*dest = *from
|
||||||
|
if dest.AutoUserNs {
|
||||||
|
overrides := c.getUserOverrides()
|
||||||
|
dest.AutoUserNsOpts.PasswdFile = overrides.ContainerEtcPasswdPath
|
||||||
|
dest.AutoUserNsOpts.GroupFile = overrides.ContainerEtcGroupPath
|
||||||
|
if c.config.User != "" {
|
||||||
|
initialSize := uint32(0)
|
||||||
|
parts := strings.Split(c.config.User, ":")
|
||||||
|
for _, p := range parts {
|
||||||
|
s, err := strconv.ParseUint(p, 10, 32)
|
||||||
|
if err == nil && uint32(s) > initialSize {
|
||||||
|
initialSize = uint32(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dest.AutoUserNsOpts.InitialSize = initialSize + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create container root filesystem for use
|
// Create container root filesystem for use
|
||||||
func (c *Container) setupStorage(ctx context.Context) error {
|
func (c *Container) setupStorage(ctx context.Context) error {
|
||||||
span, _ := opentracing.StartSpanFromContext(ctx, "setupStorage")
|
span, _ := opentracing.StartSpanFromContext(ctx, "setupStorage")
|
||||||
@ -398,14 +421,20 @@ func (c *Container) setupStorage(ctx context.Context) error {
|
|||||||
options.MountOpts = newOptions
|
options.MountOpts = newOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.config.Rootfs == "" {
|
c.setupStorageMapping(&options.IDMappingOptions, &c.config.IDMappings)
|
||||||
options.IDMappingOptions = c.config.IDMappings
|
|
||||||
}
|
|
||||||
containerInfo, err := c.runtime.storageService.CreateContainerStorage(ctx, c.runtime.imageContext, c.config.RootfsImageName, c.config.RootfsImageID, c.config.Name, c.config.ID, options)
|
containerInfo, err := c.runtime.storageService.CreateContainerStorage(ctx, c.runtime.imageContext, c.config.RootfsImageName, c.config.RootfsImageID, c.config.Name, c.config.ID, options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "error creating container storage")
|
return errors.Wrapf(err, "error creating container storage")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c.config.IDMappings.UIDMap = containerInfo.UIDMap
|
||||||
|
c.config.IDMappings.GIDMap = containerInfo.GIDMap
|
||||||
|
c.config.ProcessLabel = containerInfo.ProcessLabel
|
||||||
|
c.config.MountLabel = containerInfo.MountLabel
|
||||||
|
c.config.StaticDir = containerInfo.Dir
|
||||||
|
c.state.RunDir = containerInfo.RunDir
|
||||||
|
|
||||||
if len(c.config.IDMappings.UIDMap) != 0 || len(c.config.IDMappings.GIDMap) != 0 {
|
if len(c.config.IDMappings.UIDMap) != 0 || len(c.config.IDMappings.GIDMap) != 0 {
|
||||||
if err := os.Chown(containerInfo.RunDir, c.RootUID(), c.RootGID()); err != nil {
|
if err := os.Chown(containerInfo.RunDir, c.RootUID(), c.RootGID()); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -416,11 +445,6 @@ func (c *Container) setupStorage(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
c.config.ProcessLabel = containerInfo.ProcessLabel
|
|
||||||
c.config.MountLabel = containerInfo.MountLabel
|
|
||||||
c.config.StaticDir = containerInfo.Dir
|
|
||||||
c.state.RunDir = containerInfo.RunDir
|
|
||||||
|
|
||||||
// Set the default Entrypoint and Command
|
// Set the default Entrypoint and Command
|
||||||
if containerInfo.Config != nil {
|
if containerInfo.Config != nil {
|
||||||
if c.config.Entrypoint == nil {
|
if c.config.Entrypoint == nil {
|
||||||
|
@ -396,6 +396,20 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c.config.IDMappings.AutoUserNs {
|
||||||
|
if err := g.AddOrReplaceLinuxNamespace(string(spec.UserNamespace), ""); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
g.ClearLinuxUIDMappings()
|
||||||
|
for _, uidmap := range c.config.IDMappings.UIDMap {
|
||||||
|
g.AddLinuxUIDMapping(uint32(uidmap.HostID), uint32(uidmap.ContainerID), uint32(uidmap.Size))
|
||||||
|
}
|
||||||
|
g.ClearLinuxGIDMappings()
|
||||||
|
for _, gidmap := range c.config.IDMappings.GIDMap {
|
||||||
|
g.AddLinuxGIDMapping(uint32(gidmap.HostID), uint32(gidmap.ContainerID), uint32(gidmap.Size))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
g.SetRootPath(c.state.Mountpoint)
|
g.SetRootPath(c.state.Mountpoint)
|
||||||
g.AddAnnotation(annotations.Created, c.config.CreatedTime.Format(time.RFC3339Nano))
|
g.AddAnnotation(annotations.Created, c.config.CreatedTime.Format(time.RFC3339Nano))
|
||||||
g.AddAnnotation("org.opencontainers.image.stopSignal", fmt.Sprintf("%d", c.config.StopSignal))
|
g.AddAnnotation("org.opencontainers.image.stopSignal", fmt.Sprintf("%d", c.config.StopSignal))
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/containers/libpod/libpod/define"
|
"github.com/containers/libpod/libpod/define"
|
||||||
|
"github.com/containers/libpod/pkg/lookup"
|
||||||
spec "github.com/opencontainers/runtime-spec/specs-go"
|
spec "github.com/opencontainers/runtime-spec/specs-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -44,3 +45,7 @@ func (c *Container) copyOwnerAndPerms(source, dest string) error {
|
|||||||
func (c *Container) getOCICgroupPath() (string, error) {
|
func (c *Container) getOCICgroupPath() (string, error) {
|
||||||
return "", define.ErrNotImplemented
|
return "", define.ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Container) getUserOverrides() *lookup.Overrides {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
"github.com/containers/image/v5/types"
|
"github.com/containers/image/v5/types"
|
||||||
"github.com/containers/libpod/libpod/define"
|
"github.com/containers/libpod/libpod/define"
|
||||||
"github.com/containers/storage"
|
"github.com/containers/storage"
|
||||||
|
"github.com/containers/storage/pkg/idtools"
|
||||||
v1 "github.com/opencontainers/image-spec/specs-go/v1"
|
v1 "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
"github.com/opentracing/opentracing-go"
|
"github.com/opentracing/opentracing-go"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@ -35,6 +36,8 @@ type ContainerInfo struct {
|
|||||||
Config *v1.Image
|
Config *v1.Image
|
||||||
ProcessLabel string
|
ProcessLabel string
|
||||||
MountLabel string
|
MountLabel string
|
||||||
|
UIDMap []idtools.IDMap
|
||||||
|
GIDMap []idtools.IDMap
|
||||||
}
|
}
|
||||||
|
|
||||||
// RuntimeContainerMetadata is the structure that we encode as JSON and store
|
// RuntimeContainerMetadata is the structure that we encode as JSON and store
|
||||||
@ -166,6 +169,8 @@ func (r *storageService) CreateContainerStorage(ctx context.Context, systemConte
|
|||||||
logrus.Debugf("container %q has run directory %q", container.ID, containerRunDir)
|
logrus.Debugf("container %q has run directory %q", container.ID, containerRunDir)
|
||||||
|
|
||||||
return ContainerInfo{
|
return ContainerInfo{
|
||||||
|
UIDMap: options.UIDMap,
|
||||||
|
GIDMap: options.GIDMap,
|
||||||
Dir: containerDir,
|
Dir: containerDir,
|
||||||
RunDir: containerRunDir,
|
RunDir: containerRunDir,
|
||||||
Config: imageConfig,
|
Config: imageConfig,
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
package namespaces
|
package namespaces
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/containers/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -92,6 +96,54 @@ func (n UsernsMode) IsKeepID() bool {
|
|||||||
return n == "keep-id"
|
return n == "keep-id"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsAuto indicates whether container uses the "auto" userns mode.
|
||||||
|
func (n UsernsMode) IsAuto() bool {
|
||||||
|
parts := strings.Split(string(n), ":")
|
||||||
|
return parts[0] == "auto"
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAutoOptions returns a AutoUserNsOptions with the settings to setup automatically
|
||||||
|
// a user namespace.
|
||||||
|
func (n UsernsMode) GetAutoOptions() (*storage.AutoUserNsOptions, error) {
|
||||||
|
parts := strings.SplitN(string(n), ":", 2)
|
||||||
|
if parts[0] != "auto" {
|
||||||
|
return nil, fmt.Errorf("wrong user namespace mode")
|
||||||
|
}
|
||||||
|
options := storage.AutoUserNsOptions{}
|
||||||
|
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 "size":
|
||||||
|
s, err := strconv.ParseUint(v[1], 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
options.Size = uint32(s)
|
||||||
|
case "uidmapping":
|
||||||
|
mapping, err := storage.ParseIDMapping([]string{v[1]}, nil, "", "")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
options.AdditionalUIDMappings = append(options.AdditionalUIDMappings, mapping.UIDMap...)
|
||||||
|
case "gidmapping":
|
||||||
|
mapping, err := storage.ParseIDMapping(nil, []string{v[1]}, "", "")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
options.AdditionalGIDMappings = append(options.AdditionalGIDMappings, mapping.GIDMap...)
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unknown option specified: %q", v[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &options, nil
|
||||||
|
}
|
||||||
|
|
||||||
// IsPrivate indicates whether the container uses the a private userns.
|
// IsPrivate indicates whether the container uses the a private userns.
|
||||||
func (n UsernsMode) IsPrivate() bool {
|
func (n UsernsMode) IsPrivate() bool {
|
||||||
return !(n.IsHost() || n.IsContainer())
|
return !(n.IsHost() || n.IsContainer())
|
||||||
@ -101,7 +153,7 @@ func (n UsernsMode) IsPrivate() bool {
|
|||||||
func (n UsernsMode) Valid() bool {
|
func (n UsernsMode) Valid() bool {
|
||||||
parts := strings.Split(string(n), ":")
|
parts := strings.Split(string(n), ":")
|
||||||
switch mode := parts[0]; mode {
|
switch mode := parts[0]; mode {
|
||||||
case "", privateType, hostType, "keep-id", nsType:
|
case "", privateType, hostType, "keep-id", nsType, "auto":
|
||||||
case containerType:
|
case containerType:
|
||||||
if len(parts) != 2 || parts[1] == "" {
|
if len(parts) != 2 || parts[1] == "" {
|
||||||
return false
|
return false
|
||||||
|
@ -277,7 +277,7 @@ func (c *UserConfig) ConfigureGenerator(g *generate.Generator) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *UserConfig) getPostConfigureNetNS() bool {
|
func (c *UserConfig) getPostConfigureNetNS() bool {
|
||||||
hasUserns := c.UsernsMode.IsContainer() || c.UsernsMode.IsNS() || len(c.IDMappings.UIDMap) > 0 || len(c.IDMappings.GIDMap) > 0
|
hasUserns := c.UsernsMode.IsContainer() || c.UsernsMode.IsNS() || c.UsernsMode.IsAuto() || len(c.IDMappings.UIDMap) > 0 || len(c.IDMappings.GIDMap) > 0
|
||||||
postConfigureNetNS := hasUserns && !c.UsernsMode.IsHost()
|
postConfigureNetNS := hasUserns && !c.UsernsMode.IsHost()
|
||||||
return postConfigureNetNS
|
return postConfigureNetNS
|
||||||
}
|
}
|
||||||
@ -285,7 +285,7 @@ func (c *UserConfig) getPostConfigureNetNS() bool {
|
|||||||
// InNS returns true if the UserConfig indicates to be in a dedicated user
|
// InNS returns true if the UserConfig indicates to be in a dedicated user
|
||||||
// namespace.
|
// namespace.
|
||||||
func (c *UserConfig) InNS(isRootless bool) bool {
|
func (c *UserConfig) InNS(isRootless bool) bool {
|
||||||
hasUserns := c.UsernsMode.IsContainer() || c.UsernsMode.IsNS() || len(c.IDMappings.UIDMap) > 0 || len(c.IDMappings.GIDMap) > 0
|
hasUserns := c.UsernsMode.IsContainer() || c.UsernsMode.IsNS() || c.UsernsMode.IsAuto() || len(c.IDMappings.UIDMap) > 0 || len(c.IDMappings.GIDMap) > 0
|
||||||
return isRootless || (hasUserns && !c.UsernsMode.IsHost())
|
return isRootless || (hasUserns && !c.UsernsMode.IsHost())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -327,6 +327,18 @@ func ParseIDMapping(mode namespaces.UsernsMode, uidMapSlice, gidMapSlice []strin
|
|||||||
HostGIDMapping: true,
|
HostGIDMapping: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if mode.IsAuto() {
|
||||||
|
var err error
|
||||||
|
options.HostUIDMapping = false
|
||||||
|
options.HostGIDMapping = false
|
||||||
|
options.AutoUserNs = true
|
||||||
|
opts, err := mode.GetAutoOptions()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
options.AutoUserNsOpts = *opts
|
||||||
|
return &options, nil
|
||||||
|
}
|
||||||
if mode.IsKeepID() {
|
if mode.IsKeepID() {
|
||||||
if len(uidMapSlice) > 0 || len(gidMapSlice) > 0 {
|
if len(uidMapSlice) > 0 || len(gidMapSlice) > 0 {
|
||||||
return nil, errors.New("cannot specify custom mappings with --userns=keep-id")
|
return nil, errors.New("cannot specify custom mappings with --userns=keep-id")
|
||||||
|
@ -4,7 +4,10 @@ package integration
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"os/user"
|
||||||
|
"strings"
|
||||||
|
|
||||||
. "github.com/containers/libpod/test/utils"
|
. "github.com/containers/libpod/test/utils"
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
@ -86,6 +89,134 @@ var _ = Describe("Podman UserNS support", func() {
|
|||||||
Expect(ok).To(BeTrue())
|
Expect(ok).To(BeTrue())
|
||||||
})
|
})
|
||||||
|
|
||||||
|
It("podman --userns=auto", func() {
|
||||||
|
u, err := user.Current()
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
name := u.Name
|
||||||
|
if name == "root" {
|
||||||
|
name = "containers"
|
||||||
|
}
|
||||||
|
|
||||||
|
content, err := ioutil.ReadFile("/etc/subuid")
|
||||||
|
if err != nil {
|
||||||
|
Skip("cannot read /etc/subuid")
|
||||||
|
}
|
||||||
|
if !strings.Contains(string(content), name) {
|
||||||
|
Skip("cannot find mappings for the current user")
|
||||||
|
}
|
||||||
|
|
||||||
|
m := make(map[string]string)
|
||||||
|
for i := 0; i < 5; i++ {
|
||||||
|
session := podmanTest.Podman([]string{"run", "--userns=auto", "alpine", "cat", "/proc/self/uid_map"})
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session.ExitCode()).To(Equal(0))
|
||||||
|
l := session.OutputToString()
|
||||||
|
Expect(strings.Contains(l, "1024")).To(BeTrue())
|
||||||
|
m[l] = l
|
||||||
|
}
|
||||||
|
// check for no duplicates
|
||||||
|
Expect(len(m)).To(Equal(5))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("podman --userns=auto:size=%d", func() {
|
||||||
|
u, err := user.Current()
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
|
||||||
|
name := u.Name
|
||||||
|
if name == "root" {
|
||||||
|
name = "containers"
|
||||||
|
}
|
||||||
|
|
||||||
|
content, err := ioutil.ReadFile("/etc/subuid")
|
||||||
|
if err != nil {
|
||||||
|
Skip("cannot read /etc/subuid")
|
||||||
|
}
|
||||||
|
if !strings.Contains(string(content), name) {
|
||||||
|
Skip("cannot find mappings for the current user")
|
||||||
|
}
|
||||||
|
|
||||||
|
session := podmanTest.Podman([]string{"run", "--userns=auto:size=500", "alpine", "cat", "/proc/self/uid_map"})
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session.ExitCode()).To(Equal(0))
|
||||||
|
ok, _ := session.GrepString("500")
|
||||||
|
|
||||||
|
session = podmanTest.Podman([]string{"run", "--userns=auto:size=3000", "alpine", "cat", "/proc/self/uid_map"})
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session.ExitCode()).To(Equal(0))
|
||||||
|
ok, _ = session.GrepString("3000")
|
||||||
|
|
||||||
|
session = podmanTest.Podman([]string{"run", "--userns=auto", "--user=2000:3000", "alpine", "cat", "/proc/self/uid_map"})
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session.ExitCode()).To(Equal(0))
|
||||||
|
ok, _ = session.GrepString("3001")
|
||||||
|
|
||||||
|
session = podmanTest.Podman([]string{"run", "--userns=auto", "--user=4000:1000", "alpine", "cat", "/proc/self/uid_map"})
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session.ExitCode()).To(Equal(0))
|
||||||
|
ok, _ = session.GrepString("4001")
|
||||||
|
Expect(ok).To(BeTrue())
|
||||||
|
})
|
||||||
|
|
||||||
|
It("podman --userns=auto:uidmapping=", func() {
|
||||||
|
u, err := user.Current()
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
|
||||||
|
name := u.Name
|
||||||
|
if name == "root" {
|
||||||
|
name = "containers"
|
||||||
|
}
|
||||||
|
|
||||||
|
content, err := ioutil.ReadFile("/etc/subuid")
|
||||||
|
if err != nil {
|
||||||
|
Skip("cannot read /etc/subuid")
|
||||||
|
}
|
||||||
|
if !strings.Contains(string(content), name) {
|
||||||
|
Skip("cannot find mappings for the current user")
|
||||||
|
}
|
||||||
|
|
||||||
|
session := podmanTest.Podman([]string{"run", "--userns=auto:uidmapping=0:0:1", "alpine", "cat", "/proc/self/uid_map"})
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session.ExitCode()).To(Equal(0))
|
||||||
|
output := session.OutputToString()
|
||||||
|
Expect(output).To(MatchRegexp("\\s0\\s0\\s1"))
|
||||||
|
|
||||||
|
session = podmanTest.Podman([]string{"run", "--userns=auto:size=8192,uidmapping=0:0:1", "alpine", "cat", "/proc/self/uid_map"})
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session.ExitCode()).To(Equal(0))
|
||||||
|
ok, _ := session.GrepString("8191")
|
||||||
|
Expect(ok).To(BeTrue())
|
||||||
|
})
|
||||||
|
|
||||||
|
It("podman --userns=auto:gidmapping=", func() {
|
||||||
|
u, err := user.Current()
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
|
||||||
|
name := u.Name
|
||||||
|
if name == "root" {
|
||||||
|
name = "containers"
|
||||||
|
}
|
||||||
|
|
||||||
|
content, err := ioutil.ReadFile("/etc/subuid")
|
||||||
|
if err != nil {
|
||||||
|
Skip("cannot read /etc/subuid")
|
||||||
|
}
|
||||||
|
if !strings.Contains(string(content), name) {
|
||||||
|
Skip("cannot find mappings for the current user")
|
||||||
|
}
|
||||||
|
|
||||||
|
session := podmanTest.Podman([]string{"run", "--userns=auto:gidmapping=0:0:1", "alpine", "cat", "/proc/self/gid_map"})
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session.ExitCode()).To(Equal(0))
|
||||||
|
output := session.OutputToString()
|
||||||
|
Expect(output).To(MatchRegexp("\\s0\\s0\\s1"))
|
||||||
|
|
||||||
|
session = podmanTest.Podman([]string{"run", "--userns=auto:size=8192,gidmapping=0:0:1", "alpine", "cat", "/proc/self/gid_map"})
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session.ExitCode()).To(Equal(0))
|
||||||
|
ok, _ := session.GrepString("8191")
|
||||||
|
Expect(ok).To(BeTrue())
|
||||||
|
})
|
||||||
|
|
||||||
It("podman --userns=container:CTR", func() {
|
It("podman --userns=container:CTR", func() {
|
||||||
ctrName := "userns-ctr"
|
ctrName := "userns-ctr"
|
||||||
session := podmanTest.Podman([]string{"run", "-d", "--uidmap=0:0:1", "--uidmap=1:1:4998", "--name", ctrName, "alpine", "top"})
|
session := podmanTest.Podman([]string{"run", "-d", "--uidmap=0:0:1", "--uidmap=1:1:4998", "--name", ctrName, "alpine", "top"})
|
||||||
|
Reference in New Issue
Block a user