support user remapping in ctr
* --uidmap support for one remapping * --gidmap support for one remapping * create IoUid and IoGid options for getNewTaskOpts Signed-off-by: Jie Hao Liao <liaojh1998@gmail.com>
This commit is contained in:
parent
f01665aa02
commit
9862cb8f85
@ -20,7 +20,9 @@ package run
|
||||
|
||||
import (
|
||||
gocontext "context"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/containerd/containerd"
|
||||
@ -44,6 +46,14 @@ var platformRunFlags = []cli.Flag{
|
||||
Name: "runc-systemd-cgroup",
|
||||
Usage: "start runc with systemd cgroup manager",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "uidmap",
|
||||
Usage: "run inside a user namespace with the specified UID mapping range; specified with the format `container-uid:host-uid:length`",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "gidmap",
|
||||
Usage: "run inside a user namespace with the specified GID mapping range; specified with the format `container-gid:host-gid:length`",
|
||||
},
|
||||
}
|
||||
|
||||
// NewContainer creates a new container
|
||||
@ -115,12 +125,30 @@ func NewContainer(ctx gocontext.Context, client *containerd.Client, context *cli
|
||||
opts = append(opts, oci.WithImageConfig(image))
|
||||
cOpts = append(cOpts,
|
||||
containerd.WithImage(image),
|
||||
containerd.WithSnapshotter(snapshotter),
|
||||
containerd.WithSnapshotter(snapshotter))
|
||||
if uidmap, gidmap := context.String("uidmap"), context.String("gidmap"); uidmap != "" && gidmap != "" {
|
||||
uidMap, err := parseIDMapping(uidmap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
gidMap, err := parseIDMapping(gidmap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
opts = append(opts,
|
||||
oci.WithUserNamespace([]specs.LinuxIDMapping{uidMap}, []specs.LinuxIDMapping{gidMap}))
|
||||
if context.Bool("read-only") {
|
||||
cOpts = append(cOpts, containerd.WithRemappedSnapshotView(id, image, uidMap.HostID, gidMap.HostID))
|
||||
} else {
|
||||
cOpts = append(cOpts, containerd.WithRemappedSnapshot(id, image, uidMap.HostID, gidMap.HostID))
|
||||
}
|
||||
} else {
|
||||
// Even when "read-only" is set, we don't use KindView snapshot here. (#1495)
|
||||
// We pass writable snapshot to the OCI runtime, and the runtime remounts it as read-only,
|
||||
// after creating some mount points on demand.
|
||||
containerd.WithNewSnapshot(id, image),
|
||||
containerd.WithImageStopSignal(image, "SIGTERM"))
|
||||
cOpts = append(cOpts, containerd.WithNewSnapshot(id, image))
|
||||
}
|
||||
cOpts = append(cOpts, containerd.WithImageStopSignal(image, "SIGTERM"))
|
||||
}
|
||||
if context.Bool("read-only") {
|
||||
opts = append(opts, oci.WithRootFSReadonly())
|
||||
@ -210,10 +238,51 @@ func NewContainer(ctx gocontext.Context, client *containerd.Client, context *cli
|
||||
}
|
||||
|
||||
func getNewTaskOpts(context *cli.Context) []containerd.NewTaskOpts {
|
||||
var (
|
||||
tOpts []containerd.NewTaskOpts
|
||||
)
|
||||
if context.Bool("no-pivot") {
|
||||
return []containerd.NewTaskOpts{containerd.WithNoPivotRoot}
|
||||
tOpts = append(tOpts, containerd.WithNoPivotRoot)
|
||||
}
|
||||
return nil
|
||||
if uidmap := context.String("uidmap"); uidmap != "" {
|
||||
uidMap, err := parseIDMapping(uidmap)
|
||||
if err != nil {
|
||||
fmt.Printf("warning: expected to parse uidmap: %s\n", err.Error())
|
||||
}
|
||||
tOpts = append(tOpts, containerd.WithUIDOwner(uidMap.HostID))
|
||||
}
|
||||
if gidmap := context.String("gidmap"); gidmap != "" {
|
||||
gidMap, err := parseIDMapping(gidmap)
|
||||
if err != nil {
|
||||
fmt.Printf("warning: expected to parse uidmap: %s\n", err.Error())
|
||||
}
|
||||
tOpts = append(tOpts, containerd.WithGIDOwner(gidMap.HostID))
|
||||
}
|
||||
return tOpts
|
||||
}
|
||||
|
||||
func parseIDMapping(mapping string) (specs.LinuxIDMapping, error) {
|
||||
parts := strings.Split(mapping, ":")
|
||||
if len(parts) != 3 {
|
||||
return specs.LinuxIDMapping{}, errors.New("user namespace mappings require the format `container-id:host-id:size`")
|
||||
}
|
||||
cID, err := strconv.ParseUint(parts[0], 0, 16)
|
||||
if err != nil {
|
||||
return specs.LinuxIDMapping{}, errors.Wrapf(err, "invalid container id for user namespace remapping")
|
||||
}
|
||||
hID, err := strconv.ParseUint(parts[1], 0, 16)
|
||||
if err != nil {
|
||||
return specs.LinuxIDMapping{}, errors.Wrapf(err, "invalid host id for user namespace remapping")
|
||||
}
|
||||
size, err := strconv.ParseUint(parts[2], 0, 16)
|
||||
if err != nil {
|
||||
return specs.LinuxIDMapping{}, errors.Wrapf(err, "invalid size for user namespace remapping")
|
||||
}
|
||||
return specs.LinuxIDMapping{
|
||||
ContainerID: uint32(cID),
|
||||
HostID: uint32(hID),
|
||||
Size: uint32(size),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func validNamespace(ns string) bool {
|
||||
|
@ -103,3 +103,55 @@ func WithShimCgroup(path string) NewTaskOpts {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithUIDOwner allows console I/O to work with the remapped UID in user namespace
|
||||
func WithUIDOwner(uid uint32) NewTaskOpts {
|
||||
return func(ctx context.Context, c *Client, ti *TaskInfo) error {
|
||||
if CheckRuntime(ti.Runtime(), "io.containerd.runc") {
|
||||
if ti.Options == nil {
|
||||
ti.Options = &options.Options{}
|
||||
}
|
||||
opts, ok := ti.Options.(*options.Options)
|
||||
if !ok {
|
||||
return errors.New("invalid v2 shim create options format")
|
||||
}
|
||||
opts.IoUid = uid
|
||||
} else {
|
||||
if ti.Options == nil {
|
||||
ti.Options = &runctypes.CreateOptions{}
|
||||
}
|
||||
opts, ok := ti.Options.(*runctypes.CreateOptions)
|
||||
if !ok {
|
||||
return errors.New("could not cast TaskInfo Options to CreateOptions")
|
||||
}
|
||||
opts.IoUid = uid
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithGIDOwner allows console I/O to work with the remapped GID in user namespace
|
||||
func WithGIDOwner(gid uint32) NewTaskOpts {
|
||||
return func(ctx context.Context, c *Client, ti *TaskInfo) error {
|
||||
if CheckRuntime(ti.Runtime(), "io.containerd.runc") {
|
||||
if ti.Options == nil {
|
||||
ti.Options = &options.Options{}
|
||||
}
|
||||
opts, ok := ti.Options.(*options.Options)
|
||||
if !ok {
|
||||
return errors.New("invalid v2 shim create options format")
|
||||
}
|
||||
opts.IoGid = gid
|
||||
} else {
|
||||
if ti.Options == nil {
|
||||
ti.Options = &runctypes.CreateOptions{}
|
||||
}
|
||||
opts, ok := ti.Options.(*runctypes.CreateOptions)
|
||||
if !ok {
|
||||
return errors.New("could not cast TaskInfo Options to CreateOptions")
|
||||
}
|
||||
opts.IoGid = gid
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user