mirror of
https://github.com/containers/podman.git
synced 2025-06-05 22:31:06 +08:00
Split up create config handling of namespaces and security
As it stands, createconfig is a huge struct. This works fine when the only caller is when we create a container with a fully created config. However, if we wish to share code for security and namespace configuration, a single large struct becomes unweildy, as well as difficult to configure with the single createConfigToOCISpec function. This PR breaks up namespace and security configuration into their own structs, with the eventual goal of allowing the namespace/security fields to be configured by the pod create cli, and allow the infra container to share this with the pod's containers. Signed-off-by: Peter Hunt <pehunt@redhat.com>
This commit is contained in:
@ -26,7 +26,6 @@ import (
|
|||||||
"github.com/docker/docker/pkg/signal"
|
"github.com/docker/docker/pkg/signal"
|
||||||
"github.com/docker/go-connections/nat"
|
"github.com/docker/go-connections/nat"
|
||||||
"github.com/docker/go-units"
|
"github.com/docker/go-units"
|
||||||
"github.com/opencontainers/selinux/go-selinux/label"
|
|
||||||
"github.com/opentracing/opentracing-go"
|
"github.com/opentracing/opentracing-go"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
@ -195,72 +194,6 @@ func CreateContainer(ctx context.Context, c *GenericCLIResults, runtime *libpod.
|
|||||||
return ctr, createConfig, nil
|
return ctr, createConfig, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseSecurityOpt(config *cc.CreateConfig, securityOpts []string, runtime *libpod.Runtime) error {
|
|
||||||
var (
|
|
||||||
labelOpts []string
|
|
||||||
)
|
|
||||||
|
|
||||||
if config.PidMode.IsHost() {
|
|
||||||
labelOpts = append(labelOpts, label.DisableSecOpt()...)
|
|
||||||
} else if config.PidMode.IsContainer() {
|
|
||||||
ctr, err := runtime.LookupContainer(config.PidMode.Container())
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrapf(err, "container %q not found", config.PidMode.Container())
|
|
||||||
}
|
|
||||||
secopts, err := label.DupSecOpt(ctr.ProcessLabel())
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrapf(err, "failed to duplicate label %q ", ctr.ProcessLabel())
|
|
||||||
}
|
|
||||||
labelOpts = append(labelOpts, secopts...)
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.IpcMode.IsHost() {
|
|
||||||
labelOpts = append(labelOpts, label.DisableSecOpt()...)
|
|
||||||
} else if config.IpcMode.IsContainer() {
|
|
||||||
ctr, err := runtime.LookupContainer(config.IpcMode.Container())
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrapf(err, "container %q not found", config.IpcMode.Container())
|
|
||||||
}
|
|
||||||
secopts, err := label.DupSecOpt(ctr.ProcessLabel())
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrapf(err, "failed to duplicate label %q ", ctr.ProcessLabel())
|
|
||||||
}
|
|
||||||
labelOpts = append(labelOpts, secopts...)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, opt := range securityOpts {
|
|
||||||
if opt == "no-new-privileges" {
|
|
||||||
config.NoNewPrivs = true
|
|
||||||
} else {
|
|
||||||
con := strings.SplitN(opt, "=", 2)
|
|
||||||
if len(con) != 2 {
|
|
||||||
return fmt.Errorf("invalid --security-opt 1: %q", opt)
|
|
||||||
}
|
|
||||||
|
|
||||||
switch con[0] {
|
|
||||||
case "label":
|
|
||||||
labelOpts = append(labelOpts, con[1])
|
|
||||||
case "apparmor":
|
|
||||||
config.ApparmorProfile = con[1]
|
|
||||||
case "seccomp":
|
|
||||||
config.SeccompProfilePath = con[1]
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("invalid --security-opt 2: %q", opt)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.SeccompProfilePath == "" {
|
|
||||||
var err error
|
|
||||||
config.SeccompProfilePath, err = libpod.DefaultSeccompPath()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
config.LabelOpts = labelOpts
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func configureEntrypoint(c *GenericCLIResults, data *inspect.ImageData) []string {
|
func configureEntrypoint(c *GenericCLIResults, data *inspect.ImageData) []string {
|
||||||
entrypoint := []string{}
|
entrypoint := []string{}
|
||||||
if c.IsSet("entrypoint") {
|
if c.IsSet("entrypoint") {
|
||||||
@ -348,11 +281,6 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod.
|
|||||||
rootfs = c.InputArgs[0]
|
rootfs = c.InputArgs[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
sysctl, err := validateSysctl(c.StringSlice("sysctl"))
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "invalid value for sysctl")
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.String("memory") != "" {
|
if c.String("memory") != "" {
|
||||||
memoryLimit, err = units.RAMInBytes(c.String("memory"))
|
memoryLimit, err = units.RAMInBytes(c.String("memory"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -691,61 +619,96 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod.
|
|||||||
pidsLimit = 0
|
pidsLimit = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pid := &cc.PidConfig{
|
||||||
|
PidMode: pidMode,
|
||||||
|
}
|
||||||
|
ipc := &cc.IpcConfig{
|
||||||
|
IpcMode: ipcMode,
|
||||||
|
}
|
||||||
|
|
||||||
|
cgroup := &cc.CgroupConfig{
|
||||||
|
Cgroups: c.String("cgroups"),
|
||||||
|
Cgroupns: c.String("cgroupns"),
|
||||||
|
CgroupParent: c.String("cgroup-parent"),
|
||||||
|
CgroupMode: cgroupMode,
|
||||||
|
}
|
||||||
|
|
||||||
|
userns := &cc.UserConfig{
|
||||||
|
GroupAdd: c.StringSlice("group-add"),
|
||||||
|
IDMappings: idmappings,
|
||||||
|
UsernsMode: usernsMode,
|
||||||
|
User: user,
|
||||||
|
}
|
||||||
|
|
||||||
|
uts := &cc.UtsConfig{
|
||||||
|
UtsMode: utsMode,
|
||||||
|
NoHosts: c.Bool("no-hosts"),
|
||||||
|
HostAdd: c.StringSlice("add-host"),
|
||||||
|
Hostname: c.String("hostname"),
|
||||||
|
}
|
||||||
|
|
||||||
|
net := &cc.NetworkConfig{
|
||||||
|
DNSOpt: c.StringSlice("dns-opt"),
|
||||||
|
DNSSearch: c.StringSlice("dns-search"),
|
||||||
|
DNSServers: c.StringSlice("dns"),
|
||||||
|
HTTPProxy: c.Bool("http-proxy"),
|
||||||
|
MacAddress: c.String("mac-address"),
|
||||||
|
Network: network,
|
||||||
|
NetMode: netMode,
|
||||||
|
IPAddress: c.String("ip"),
|
||||||
|
Publish: c.StringSlice("publish"),
|
||||||
|
PublishAll: c.Bool("publish-all"),
|
||||||
|
PortBindings: portBindings,
|
||||||
|
}
|
||||||
|
|
||||||
|
sysctl, err := validateSysctl(c.StringSlice("sysctl"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "invalid value for sysctl")
|
||||||
|
}
|
||||||
|
|
||||||
|
secConfig := &cc.SecurityConfig{
|
||||||
|
CapAdd: c.StringSlice("cap-add"),
|
||||||
|
CapDrop: c.StringSlice("cap-drop"),
|
||||||
|
Privileged: c.Bool("privileged"),
|
||||||
|
ReadOnlyRootfs: c.Bool("read-only"),
|
||||||
|
ReadOnlyTmpfs: c.Bool("read-only-tmpfs"),
|
||||||
|
Sysctl: sysctl,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := secConfig.SetLabelOpts(runtime, pid, ipc); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := secConfig.SetSecurityOpts(runtime, c.StringArray("security-opt")); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
config := &cc.CreateConfig{
|
config := &cc.CreateConfig{
|
||||||
Annotations: annotations,
|
Annotations: annotations,
|
||||||
BuiltinImgVolumes: ImageVolumes,
|
BuiltinImgVolumes: ImageVolumes,
|
||||||
ConmonPidFile: c.String("conmon-pidfile"),
|
ConmonPidFile: c.String("conmon-pidfile"),
|
||||||
ImageVolumeType: c.String("image-volume"),
|
ImageVolumeType: c.String("image-volume"),
|
||||||
CapAdd: c.StringSlice("cap-add"),
|
|
||||||
CapDrop: c.StringSlice("cap-drop"),
|
|
||||||
CidFile: c.String("cidfile"),
|
CidFile: c.String("cidfile"),
|
||||||
Cgroupns: c.String("cgroupns"),
|
|
||||||
Cgroups: c.String("cgroups"),
|
|
||||||
CgroupParent: c.String("cgroup-parent"),
|
|
||||||
Command: command,
|
Command: command,
|
||||||
UserCommand: userCommand,
|
UserCommand: userCommand,
|
||||||
Detach: c.Bool("detach"),
|
Detach: c.Bool("detach"),
|
||||||
Devices: c.StringSlice("device"),
|
Devices: c.StringSlice("device"),
|
||||||
DNSOpt: c.StringSlice("dns-opt"),
|
|
||||||
DNSSearch: c.StringSlice("dns-search"),
|
|
||||||
DNSServers: c.StringSlice("dns"),
|
|
||||||
Entrypoint: entrypoint,
|
Entrypoint: entrypoint,
|
||||||
Env: env,
|
Env: env,
|
||||||
// ExposedPorts: ports,
|
// ExposedPorts: ports,
|
||||||
GroupAdd: c.StringSlice("group-add"),
|
|
||||||
Hostname: c.String("hostname"),
|
|
||||||
HostAdd: c.StringSlice("add-host"),
|
|
||||||
HTTPProxy: c.Bool("http-proxy"),
|
|
||||||
NoHosts: c.Bool("no-hosts"),
|
|
||||||
IDMappings: idmappings,
|
|
||||||
Init: c.Bool("init"),
|
Init: c.Bool("init"),
|
||||||
InitPath: c.String("init-path"),
|
InitPath: c.String("init-path"),
|
||||||
Image: imageName,
|
Image: imageName,
|
||||||
ImageID: imageID,
|
ImageID: imageID,
|
||||||
Interactive: c.Bool("interactive"),
|
Interactive: c.Bool("interactive"),
|
||||||
// IP6Address: c.String("ipv6"), // Not implemented yet - needs CNI support for static v6
|
// IP6Address: c.String("ipv6"), // Not implemented yet - needs CNI support for static v6
|
||||||
IPAddress: c.String("ip"),
|
Labels: labels,
|
||||||
Labels: labels,
|
|
||||||
// LinkLocalIP: c.StringSlice("link-local-ip"), // Not implemented yet
|
// LinkLocalIP: c.StringSlice("link-local-ip"), // Not implemented yet
|
||||||
LogDriver: logDriver,
|
LogDriver: logDriver,
|
||||||
LogDriverOpt: c.StringSlice("log-opt"),
|
LogDriverOpt: c.StringSlice("log-opt"),
|
||||||
MacAddress: c.String("mac-address"),
|
|
||||||
Name: c.String("name"),
|
Name: c.String("name"),
|
||||||
Network: network,
|
|
||||||
// NetworkAlias: c.StringSlice("network-alias"), // Not implemented - does this make sense in Podman?
|
// NetworkAlias: c.StringSlice("network-alias"), // Not implemented - does this make sense in Podman?
|
||||||
IpcMode: ipcMode,
|
Pod: podName,
|
||||||
NetMode: netMode,
|
Quiet: c.Bool("quiet"),
|
||||||
UtsMode: utsMode,
|
|
||||||
PidMode: pidMode,
|
|
||||||
CgroupMode: cgroupMode,
|
|
||||||
Pod: podName,
|
|
||||||
Privileged: c.Bool("privileged"),
|
|
||||||
Publish: c.StringSlice("publish"),
|
|
||||||
PublishAll: c.Bool("publish-all"),
|
|
||||||
PortBindings: portBindings,
|
|
||||||
Quiet: c.Bool("quiet"),
|
|
||||||
ReadOnlyRootfs: c.Bool("read-only"),
|
|
||||||
ReadOnlyTmpfs: c.Bool("read-only-tmpfs"),
|
|
||||||
Resources: cc.CreateResourceConfig{
|
Resources: cc.CreateResourceConfig{
|
||||||
BlkioWeight: blkioWeight,
|
BlkioWeight: blkioWeight,
|
||||||
BlkioWeightDevice: c.StringSlice("blkio-weight-device"),
|
BlkioWeightDevice: c.StringSlice("blkio-weight-device"),
|
||||||
@ -774,30 +737,27 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod.
|
|||||||
},
|
},
|
||||||
RestartPolicy: c.String("restart"),
|
RestartPolicy: c.String("restart"),
|
||||||
Rm: c.Bool("rm"),
|
Rm: c.Bool("rm"),
|
||||||
|
Security: *secConfig,
|
||||||
StopSignal: stopSignal,
|
StopSignal: stopSignal,
|
||||||
StopTimeout: c.Uint("stop-timeout"),
|
StopTimeout: c.Uint("stop-timeout"),
|
||||||
Sysctl: sysctl,
|
|
||||||
Systemd: systemd,
|
Systemd: systemd,
|
||||||
Tmpfs: c.StringArray("tmpfs"),
|
Tmpfs: c.StringArray("tmpfs"),
|
||||||
Tty: tty,
|
Tty: tty,
|
||||||
User: user,
|
|
||||||
UsernsMode: usernsMode,
|
|
||||||
MountsFlag: c.StringArray("mount"),
|
MountsFlag: c.StringArray("mount"),
|
||||||
Volumes: c.StringArray("volume"),
|
Volumes: c.StringArray("volume"),
|
||||||
WorkDir: workDir,
|
WorkDir: workDir,
|
||||||
Rootfs: rootfs,
|
Rootfs: rootfs,
|
||||||
VolumesFrom: c.StringSlice("volumes-from"),
|
VolumesFrom: c.StringSlice("volumes-from"),
|
||||||
Syslog: c.Bool("syslog"),
|
Syslog: c.Bool("syslog"),
|
||||||
|
|
||||||
|
Pid: *pid,
|
||||||
|
Ipc: *ipc,
|
||||||
|
Cgroup: *cgroup,
|
||||||
|
User: *userns,
|
||||||
|
Uts: *uts,
|
||||||
|
Network: *net,
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.Privileged {
|
|
||||||
config.LabelOpts = label.DisableSecOpt()
|
|
||||||
} else {
|
|
||||||
if err := parseSecurityOpt(config, c.StringArray("security-opt"), runtime); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
config.SecurityOpts = c.StringArray("security-opt")
|
|
||||||
warnings, err := verifyContainerResources(config, false)
|
warnings, err := verifyContainerResources(config, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -666,55 +666,55 @@ func getPodPorts(containers []v1.Container) []ocicni.PortMapping {
|
|||||||
return infraPorts
|
return infraPorts
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupSecurityContext(containerConfig *createconfig.CreateConfig, containerYAML v1.Container) {
|
func setupSecurityContext(securityConfig *createconfig.SecurityConfig, userConfig *createconfig.UserConfig, containerYAML v1.Container) {
|
||||||
if containerYAML.SecurityContext == nil {
|
if containerYAML.SecurityContext == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if containerYAML.SecurityContext.ReadOnlyRootFilesystem != nil {
|
if containerYAML.SecurityContext.ReadOnlyRootFilesystem != nil {
|
||||||
containerConfig.ReadOnlyRootfs = *containerYAML.SecurityContext.ReadOnlyRootFilesystem
|
securityConfig.ReadOnlyRootfs = *containerYAML.SecurityContext.ReadOnlyRootFilesystem
|
||||||
}
|
}
|
||||||
if containerYAML.SecurityContext.Privileged != nil {
|
if containerYAML.SecurityContext.Privileged != nil {
|
||||||
containerConfig.Privileged = *containerYAML.SecurityContext.Privileged
|
securityConfig.Privileged = *containerYAML.SecurityContext.Privileged
|
||||||
}
|
}
|
||||||
|
|
||||||
if containerYAML.SecurityContext.AllowPrivilegeEscalation != nil {
|
if containerYAML.SecurityContext.AllowPrivilegeEscalation != nil {
|
||||||
containerConfig.NoNewPrivs = !*containerYAML.SecurityContext.AllowPrivilegeEscalation
|
securityConfig.NoNewPrivs = !*containerYAML.SecurityContext.AllowPrivilegeEscalation
|
||||||
}
|
}
|
||||||
|
|
||||||
if seopt := containerYAML.SecurityContext.SELinuxOptions; seopt != nil {
|
if seopt := containerYAML.SecurityContext.SELinuxOptions; seopt != nil {
|
||||||
if seopt.User != "" {
|
if seopt.User != "" {
|
||||||
containerConfig.SecurityOpts = append(containerConfig.SecurityOpts, fmt.Sprintf("label=user:%s", seopt.User))
|
securityConfig.SecurityOpts = append(securityConfig.SecurityOpts, fmt.Sprintf("label=user:%s", seopt.User))
|
||||||
containerConfig.LabelOpts = append(containerConfig.LabelOpts, fmt.Sprintf("user:%s", seopt.User))
|
securityConfig.LabelOpts = append(securityConfig.LabelOpts, fmt.Sprintf("user:%s", seopt.User))
|
||||||
}
|
}
|
||||||
if seopt.Role != "" {
|
if seopt.Role != "" {
|
||||||
containerConfig.SecurityOpts = append(containerConfig.SecurityOpts, fmt.Sprintf("label=role:%s", seopt.Role))
|
securityConfig.SecurityOpts = append(securityConfig.SecurityOpts, fmt.Sprintf("label=role:%s", seopt.Role))
|
||||||
containerConfig.LabelOpts = append(containerConfig.LabelOpts, fmt.Sprintf("role:%s", seopt.Role))
|
securityConfig.LabelOpts = append(securityConfig.LabelOpts, fmt.Sprintf("role:%s", seopt.Role))
|
||||||
}
|
}
|
||||||
if seopt.Type != "" {
|
if seopt.Type != "" {
|
||||||
containerConfig.SecurityOpts = append(containerConfig.SecurityOpts, fmt.Sprintf("label=type:%s", seopt.Type))
|
securityConfig.SecurityOpts = append(securityConfig.SecurityOpts, fmt.Sprintf("label=type:%s", seopt.Type))
|
||||||
containerConfig.LabelOpts = append(containerConfig.LabelOpts, fmt.Sprintf("type:%s", seopt.Type))
|
securityConfig.LabelOpts = append(securityConfig.LabelOpts, fmt.Sprintf("type:%s", seopt.Type))
|
||||||
}
|
}
|
||||||
if seopt.Level != "" {
|
if seopt.Level != "" {
|
||||||
containerConfig.SecurityOpts = append(containerConfig.SecurityOpts, fmt.Sprintf("label=level:%s", seopt.Level))
|
securityConfig.SecurityOpts = append(securityConfig.SecurityOpts, fmt.Sprintf("label=level:%s", seopt.Level))
|
||||||
containerConfig.LabelOpts = append(containerConfig.LabelOpts, fmt.Sprintf("level:%s", seopt.Level))
|
securityConfig.LabelOpts = append(securityConfig.LabelOpts, fmt.Sprintf("level:%s", seopt.Level))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if caps := containerYAML.SecurityContext.Capabilities; caps != nil {
|
if caps := containerYAML.SecurityContext.Capabilities; caps != nil {
|
||||||
for _, capability := range caps.Add {
|
for _, capability := range caps.Add {
|
||||||
containerConfig.CapAdd = append(containerConfig.CapAdd, string(capability))
|
securityConfig.CapAdd = append(securityConfig.CapAdd, string(capability))
|
||||||
}
|
}
|
||||||
for _, capability := range caps.Drop {
|
for _, capability := range caps.Drop {
|
||||||
containerConfig.CapDrop = append(containerConfig.CapDrop, string(capability))
|
securityConfig.CapDrop = append(securityConfig.CapDrop, string(capability))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if containerYAML.SecurityContext.RunAsUser != nil {
|
if containerYAML.SecurityContext.RunAsUser != nil {
|
||||||
containerConfig.User = fmt.Sprintf("%d", *containerYAML.SecurityContext.RunAsUser)
|
userConfig.User = fmt.Sprintf("%d", *containerYAML.SecurityContext.RunAsUser)
|
||||||
}
|
}
|
||||||
if containerYAML.SecurityContext.RunAsGroup != nil {
|
if containerYAML.SecurityContext.RunAsGroup != nil {
|
||||||
if containerConfig.User == "" {
|
if userConfig.User == "" {
|
||||||
containerConfig.User = "0"
|
userConfig.User = "0"
|
||||||
}
|
}
|
||||||
containerConfig.User = fmt.Sprintf("%s:%d", containerConfig.User, *containerYAML.SecurityContext.RunAsGroup)
|
userConfig.User = fmt.Sprintf("%s:%d", userConfig.User, *containerYAML.SecurityContext.RunAsGroup)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -722,6 +722,13 @@ func setupSecurityContext(containerConfig *createconfig.CreateConfig, containerY
|
|||||||
func kubeContainerToCreateConfig(ctx context.Context, containerYAML v1.Container, runtime *libpod.Runtime, newImage *image.Image, namespaces map[string]string, volumes map[string]string, podID string) (*createconfig.CreateConfig, error) {
|
func kubeContainerToCreateConfig(ctx context.Context, containerYAML v1.Container, runtime *libpod.Runtime, newImage *image.Image, namespaces map[string]string, volumes map[string]string, podID string) (*createconfig.CreateConfig, error) {
|
||||||
var (
|
var (
|
||||||
containerConfig createconfig.CreateConfig
|
containerConfig createconfig.CreateConfig
|
||||||
|
pidConfig createconfig.PidConfig
|
||||||
|
networkConfig createconfig.NetworkConfig
|
||||||
|
cgroupConfig createconfig.CgroupConfig
|
||||||
|
utsConfig createconfig.UtsConfig
|
||||||
|
ipcConfig createconfig.IpcConfig
|
||||||
|
userConfig createconfig.UserConfig
|
||||||
|
securityConfig createconfig.SecurityConfig
|
||||||
)
|
)
|
||||||
|
|
||||||
// The default for MemorySwappiness is -1, not 0
|
// The default for MemorySwappiness is -1, not 0
|
||||||
@ -737,15 +744,15 @@ func kubeContainerToCreateConfig(ctx context.Context, containerYAML v1.Container
|
|||||||
|
|
||||||
imageData, _ := newImage.Inspect(ctx)
|
imageData, _ := newImage.Inspect(ctx)
|
||||||
|
|
||||||
containerConfig.User = "0"
|
userConfig.User = "0"
|
||||||
if imageData != nil {
|
if imageData != nil {
|
||||||
containerConfig.User = imageData.Config.User
|
userConfig.User = imageData.Config.User
|
||||||
}
|
}
|
||||||
|
|
||||||
setupSecurityContext(&containerConfig, containerYAML)
|
setupSecurityContext(&securityConfig, &userConfig, containerYAML)
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
containerConfig.SeccompProfilePath, err = libpod.DefaultSeccompPath()
|
containerConfig.Security.SeccompProfilePath, err = libpod.DefaultSeccompPath()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -768,20 +775,28 @@ func kubeContainerToCreateConfig(ctx context.Context, containerYAML v1.Container
|
|||||||
containerConfig.StopSignal = 15
|
containerConfig.StopSignal = 15
|
||||||
|
|
||||||
// If the user does not pass in ID mappings, just set to basics
|
// If the user does not pass in ID mappings, just set to basics
|
||||||
if containerConfig.IDMappings == nil {
|
if userConfig.IDMappings == nil {
|
||||||
containerConfig.IDMappings = &storage.IDMappingOptions{}
|
userConfig.IDMappings = &storage.IDMappingOptions{}
|
||||||
}
|
}
|
||||||
|
|
||||||
containerConfig.NetMode = ns.NetworkMode(namespaces["net"])
|
networkConfig.NetMode = ns.NetworkMode(namespaces["net"])
|
||||||
containerConfig.IpcMode = ns.IpcMode(namespaces["ipc"])
|
ipcConfig.IpcMode = ns.IpcMode(namespaces["ipc"])
|
||||||
containerConfig.UtsMode = ns.UTSMode(namespaces["uts"])
|
utsConfig.UtsMode = ns.UTSMode(namespaces["uts"])
|
||||||
// disabled in code review per mheon
|
// disabled in code review per mheon
|
||||||
//containerConfig.PidMode = ns.PidMode(namespaces["pid"])
|
//containerConfig.PidMode = ns.PidMode(namespaces["pid"])
|
||||||
containerConfig.UsernsMode = ns.UsernsMode(namespaces["user"])
|
userConfig.UsernsMode = ns.UsernsMode(namespaces["user"])
|
||||||
if len(containerConfig.WorkDir) == 0 {
|
if len(containerConfig.WorkDir) == 0 {
|
||||||
containerConfig.WorkDir = "/"
|
containerConfig.WorkDir = "/"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
containerConfig.Pid = pidConfig
|
||||||
|
containerConfig.Network = networkConfig
|
||||||
|
containerConfig.Uts = utsConfig
|
||||||
|
containerConfig.Ipc = ipcConfig
|
||||||
|
containerConfig.Cgroup = cgroupConfig
|
||||||
|
containerConfig.User = userConfig
|
||||||
|
containerConfig.Security = securityConfig
|
||||||
|
|
||||||
// Set default environment variables and incorporate data from image, if necessary
|
// Set default environment variables and incorporate data from image, if necessary
|
||||||
envs := shared.EnvVariablesFromData(imageData)
|
envs := shared.EnvVariablesFromData(imageData)
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ import (
|
|||||||
seccomp "github.com/seccomp/containers-golang"
|
seccomp "github.com/seccomp/containers-golang"
|
||||||
)
|
)
|
||||||
|
|
||||||
func getSeccompConfig(config *CreateConfig, configSpec *spec.Spec) (*spec.LinuxSeccomp, error) {
|
func getSeccompConfig(config *SecurityConfig, configSpec *spec.Spec) (*spec.LinuxSeccomp, error) {
|
||||||
var seccompConfig *spec.LinuxSeccomp
|
var seccompConfig *spec.LinuxSeccomp
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
|
@ -6,6 +6,6 @@ import (
|
|||||||
spec "github.com/opencontainers/runtime-spec/specs-go"
|
spec "github.com/opencontainers/runtime-spec/specs-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
func getSeccompConfig(config *CreateConfig, configSpec *spec.Spec) (*spec.LinuxSeccomp, error) {
|
func getSeccompConfig(config *SecurityConfig, configSpec *spec.Spec) (*spec.LinuxSeccomp, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ import (
|
|||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
func getSeccompConfig(config *CreateConfig, configSpec *spec.Spec) (*spec.LinuxSeccomp, error) {
|
func getSeccompConfig(config *SecurityConfig, configSpec *spec.Spec) (*spec.LinuxSeccomp, error) {
|
||||||
return nil, errors.New("function not supported on non-linux OS's")
|
return nil, errors.New("function not supported on non-linux OS's")
|
||||||
}
|
}
|
||||||
func addDevice(g *generate.Generator, device string) error {
|
func addDevice(g *generate.Generator, device string) error {
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package createconfig
|
package createconfig
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -12,7 +11,6 @@ import (
|
|||||||
"github.com/containers/libpod/libpod/define"
|
"github.com/containers/libpod/libpod/define"
|
||||||
"github.com/containers/libpod/pkg/namespaces"
|
"github.com/containers/libpod/pkg/namespaces"
|
||||||
"github.com/containers/storage"
|
"github.com/containers/storage"
|
||||||
"github.com/cri-o/ocicni/pkg/ocicni"
|
|
||||||
"github.com/docker/go-connections/nat"
|
"github.com/docker/go-connections/nat"
|
||||||
spec "github.com/opencontainers/runtime-spec/specs-go"
|
spec "github.com/opencontainers/runtime-spec/specs-go"
|
||||||
"github.com/opencontainers/runtime-tools/generate"
|
"github.com/opencontainers/runtime-tools/generate"
|
||||||
@ -55,89 +53,126 @@ type CreateResourceConfig struct {
|
|||||||
Ulimit []string //ulimit
|
Ulimit []string //ulimit
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateConfig is a pre OCI spec structure. It represents user input from varlink or the CLI
|
// PidConfig configures the pid namespace for the container
|
||||||
type CreateConfig struct {
|
type PidConfig struct {
|
||||||
Annotations map[string]string
|
PidMode namespaces.PidMode //pid
|
||||||
Args []string
|
}
|
||||||
|
|
||||||
|
// IpcConfig configures the ipc namespace for the container
|
||||||
|
type IpcConfig struct {
|
||||||
|
IpcMode namespaces.IpcMode //ipc
|
||||||
|
}
|
||||||
|
|
||||||
|
// CgroupConfig configures the cgroup namespace for the container
|
||||||
|
type CgroupConfig struct {
|
||||||
|
Cgroups string
|
||||||
|
Cgroupns string
|
||||||
|
CgroupParent string // cgroup-parent
|
||||||
|
CgroupMode namespaces.CgroupMode //cgroup
|
||||||
|
}
|
||||||
|
|
||||||
|
// UserConfig configures the user namespace for the container
|
||||||
|
type UserConfig struct {
|
||||||
|
GroupAdd []string // group-add
|
||||||
|
IDMappings *storage.IDMappingOptions
|
||||||
|
UsernsMode namespaces.UsernsMode //userns
|
||||||
|
User string //user
|
||||||
|
}
|
||||||
|
|
||||||
|
// UtsConfig configures the uts namespace for the container
|
||||||
|
type UtsConfig struct {
|
||||||
|
UtsMode namespaces.UTSMode //uts
|
||||||
|
NoHosts bool
|
||||||
|
HostAdd []string //add-host
|
||||||
|
Hostname string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NetworkConfig configures the network namespace for the container
|
||||||
|
type NetworkConfig struct {
|
||||||
|
DNSOpt []string //dns-opt
|
||||||
|
DNSSearch []string //dns-search
|
||||||
|
DNSServers []string //dns
|
||||||
|
ExposedPorts map[nat.Port]struct{}
|
||||||
|
HTTPProxy bool
|
||||||
|
IP6Address string //ipv6
|
||||||
|
IPAddress string //ip
|
||||||
|
LinkLocalIP []string // link-local-ip
|
||||||
|
MacAddress string //mac-address
|
||||||
|
NetMode namespaces.NetworkMode //net
|
||||||
|
Network string //network
|
||||||
|
NetworkAlias []string //network-alias
|
||||||
|
PortBindings nat.PortMap
|
||||||
|
Publish []string //publish
|
||||||
|
PublishAll bool //publish-all
|
||||||
|
}
|
||||||
|
|
||||||
|
// SecurityConfig configures the security features for the container
|
||||||
|
type SecurityConfig struct {
|
||||||
CapAdd []string // cap-add
|
CapAdd []string // cap-add
|
||||||
CapDrop []string // cap-drop
|
CapDrop []string // cap-drop
|
||||||
CidFile string
|
|
||||||
ConmonPidFile string
|
|
||||||
Cgroupns string
|
|
||||||
Cgroups string
|
|
||||||
CgroupParent string // cgroup-parent
|
|
||||||
Command []string // Full command that will be used
|
|
||||||
UserCommand []string // User-entered command (or image CMD)
|
|
||||||
Detach bool // detach
|
|
||||||
Devices []string // device
|
|
||||||
DNSOpt []string //dns-opt
|
|
||||||
DNSSearch []string //dns-search
|
|
||||||
DNSServers []string //dns
|
|
||||||
Entrypoint []string //entrypoint
|
|
||||||
Env map[string]string //env
|
|
||||||
ExposedPorts map[nat.Port]struct{}
|
|
||||||
GroupAdd []string // group-add
|
|
||||||
HealthCheck *manifest.Schema2HealthConfig
|
|
||||||
NoHosts bool
|
|
||||||
HostAdd []string //add-host
|
|
||||||
Hostname string //hostname
|
|
||||||
HTTPProxy bool
|
|
||||||
Init bool // init
|
|
||||||
InitPath string //init-path
|
|
||||||
Image string
|
|
||||||
ImageID string
|
|
||||||
BuiltinImgVolumes map[string]struct{} // volumes defined in the image config
|
|
||||||
IDMappings *storage.IDMappingOptions
|
|
||||||
ImageVolumeType string // how to handle the image volume, either bind, tmpfs, or ignore
|
|
||||||
Interactive bool //interactive
|
|
||||||
IpcMode namespaces.IpcMode //ipc
|
|
||||||
IP6Address string //ipv6
|
|
||||||
IPAddress string //ip
|
|
||||||
Labels map[string]string //label
|
|
||||||
LinkLocalIP []string // link-local-ip
|
|
||||||
LogDriver string // log-driver
|
|
||||||
LogDriverOpt []string // log-opt
|
|
||||||
MacAddress string //mac-address
|
|
||||||
Name string //name
|
|
||||||
NetMode namespaces.NetworkMode //net
|
|
||||||
Network string //network
|
|
||||||
NetworkAlias []string //network-alias
|
|
||||||
PidMode namespaces.PidMode //pid
|
|
||||||
Pod string //pod
|
|
||||||
PodmanPath string
|
|
||||||
CgroupMode namespaces.CgroupMode //cgroup
|
|
||||||
PortBindings nat.PortMap
|
|
||||||
Privileged bool //privileged
|
|
||||||
Publish []string //publish
|
|
||||||
PublishAll bool //publish-all
|
|
||||||
Quiet bool //quiet
|
|
||||||
ReadOnlyRootfs bool //read-only
|
|
||||||
ReadOnlyTmpfs bool //read-only-tmpfs
|
|
||||||
Resources CreateResourceConfig
|
|
||||||
RestartPolicy string
|
|
||||||
Rm bool //rm
|
|
||||||
StopSignal syscall.Signal // stop-signal
|
|
||||||
StopTimeout uint // stop-timeout
|
|
||||||
Sysctl map[string]string //sysctl
|
|
||||||
Systemd bool
|
|
||||||
Tmpfs []string // tmpfs
|
|
||||||
Tty bool //tty
|
|
||||||
UsernsMode namespaces.UsernsMode //userns
|
|
||||||
User string //user
|
|
||||||
UtsMode namespaces.UTSMode //uts
|
|
||||||
Mounts []spec.Mount
|
|
||||||
MountsFlag []string // mounts
|
|
||||||
NamedVolumes []*libpod.ContainerNamedVolume
|
|
||||||
Volumes []string //volume
|
|
||||||
VolumesFrom []string
|
|
||||||
WorkDir string //workdir
|
|
||||||
LabelOpts []string //SecurityOpts
|
LabelOpts []string //SecurityOpts
|
||||||
NoNewPrivs bool //SecurityOpts
|
NoNewPrivs bool //SecurityOpts
|
||||||
ApparmorProfile string //SecurityOpts
|
ApparmorProfile string //SecurityOpts
|
||||||
SeccompProfilePath string //SecurityOpts
|
SeccompProfilePath string //SecurityOpts
|
||||||
SecurityOpts []string
|
SecurityOpts []string
|
||||||
Rootfs string
|
Privileged bool //privileged
|
||||||
Syslog bool // Whether to enable syslog on exit commands
|
ReadOnlyRootfs bool //read-only
|
||||||
|
ReadOnlyTmpfs bool //read-only-tmpfs
|
||||||
|
Sysctl map[string]string //sysctl
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateConfig is a pre OCI spec structure. It represents user input from varlink or the CLI
|
||||||
|
type CreateConfig struct {
|
||||||
|
Annotations map[string]string
|
||||||
|
Args []string
|
||||||
|
CidFile string
|
||||||
|
ConmonPidFile string
|
||||||
|
Command []string // Full command that will be used
|
||||||
|
UserCommand []string // User-entered command (or image CMD)
|
||||||
|
Detach bool // detach
|
||||||
|
Devices []string // device
|
||||||
|
Entrypoint []string //entrypoint
|
||||||
|
Env map[string]string //env
|
||||||
|
HealthCheck *manifest.Schema2HealthConfig
|
||||||
|
Init bool // init
|
||||||
|
InitPath string //init-path
|
||||||
|
Image string
|
||||||
|
ImageID string
|
||||||
|
BuiltinImgVolumes map[string]struct{} // volumes defined in the image config
|
||||||
|
ImageVolumeType string // how to handle the image volume, either bind, tmpfs, or ignore
|
||||||
|
Interactive bool //interactive
|
||||||
|
Labels map[string]string //label
|
||||||
|
LogDriver string // log-driver
|
||||||
|
LogDriverOpt []string // log-opt
|
||||||
|
Name string //name
|
||||||
|
PodmanPath string
|
||||||
|
Pod string //pod
|
||||||
|
Quiet bool //quiet
|
||||||
|
Resources CreateResourceConfig
|
||||||
|
RestartPolicy string
|
||||||
|
Rm bool //rm
|
||||||
|
StopSignal syscall.Signal // stop-signal
|
||||||
|
StopTimeout uint // stop-timeout
|
||||||
|
Systemd bool
|
||||||
|
Tmpfs []string // tmpfs
|
||||||
|
Tty bool //tty
|
||||||
|
Mounts []spec.Mount
|
||||||
|
MountsFlag []string // mounts
|
||||||
|
NamedVolumes []*libpod.ContainerNamedVolume
|
||||||
|
Volumes []string //volume
|
||||||
|
VolumesFrom []string
|
||||||
|
WorkDir string //workdir
|
||||||
|
Rootfs string
|
||||||
|
Security SecurityConfig
|
||||||
|
Syslog bool // Whether to enable syslog on exit commands
|
||||||
|
|
||||||
|
// Namespaces
|
||||||
|
Pid PidConfig
|
||||||
|
Ipc IpcConfig
|
||||||
|
Cgroup CgroupConfig
|
||||||
|
User UserConfig
|
||||||
|
Uts UtsConfig
|
||||||
|
Network NetworkConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
func u32Ptr(i int64) *uint32 { u := uint32(i); return &u }
|
func u32Ptr(i int64) *uint32 { u := uint32(i); return &u }
|
||||||
@ -199,7 +234,6 @@ func (c *CreateConfig) createExitCommand(runtime *libpod.Runtime) ([]string, err
|
|||||||
// GetContainerCreateOptions takes a CreateConfig and returns a slice of CtrCreateOptions
|
// GetContainerCreateOptions takes a CreateConfig and returns a slice of CtrCreateOptions
|
||||||
func (c *CreateConfig) getContainerCreateOptions(runtime *libpod.Runtime, pod *libpod.Pod, mounts []spec.Mount, namedVolumes []*libpod.ContainerNamedVolume) ([]libpod.CtrCreateOption, error) {
|
func (c *CreateConfig) getContainerCreateOptions(runtime *libpod.Runtime, pod *libpod.Pod, mounts []spec.Mount, namedVolumes []*libpod.ContainerNamedVolume) ([]libpod.CtrCreateOption, error) {
|
||||||
var options []libpod.CtrCreateOption
|
var options []libpod.CtrCreateOption
|
||||||
var portBindings []ocicni.PortMapping
|
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
if c.Interactive {
|
if c.Interactive {
|
||||||
@ -216,15 +250,6 @@ func (c *CreateConfig) getContainerCreateOptions(runtime *libpod.Runtime, pod *l
|
|||||||
logrus.Debugf("adding container to pod %s", c.Pod)
|
logrus.Debugf("adding container to pod %s", c.Pod)
|
||||||
options = append(options, runtime.WithPod(pod))
|
options = append(options, runtime.WithPod(pod))
|
||||||
}
|
}
|
||||||
if c.Cgroups == "disabled" {
|
|
||||||
options = append(options, libpod.WithNoCgroups())
|
|
||||||
}
|
|
||||||
if len(c.PortBindings) > 0 {
|
|
||||||
portBindings, err = c.CreatePortBindings()
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "unable to create port bindings")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(mounts) != 0 || len(namedVolumes) != 0 {
|
if len(mounts) != 0 || len(namedVolumes) != 0 {
|
||||||
destinations := []string{}
|
destinations := []string{}
|
||||||
@ -253,130 +278,10 @@ func (c *CreateConfig) getContainerCreateOptions(runtime *libpod.Runtime, pod *l
|
|||||||
// does not have one
|
// does not have one
|
||||||
options = append(options, libpod.WithEntrypoint(c.Entrypoint))
|
options = append(options, libpod.WithEntrypoint(c.Entrypoint))
|
||||||
|
|
||||||
networks := make([]string, 0)
|
|
||||||
userNetworks := c.NetMode.UserDefined()
|
|
||||||
if IsPod(userNetworks) {
|
|
||||||
userNetworks = ""
|
|
||||||
}
|
|
||||||
if userNetworks != "" {
|
|
||||||
for _, netName := range strings.Split(userNetworks, ",") {
|
|
||||||
if netName == "" {
|
|
||||||
return nil, errors.Wrapf(err, "container networks %q invalid", networks)
|
|
||||||
}
|
|
||||||
networks = append(networks, netName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.NetMode.IsNS() {
|
|
||||||
ns := c.NetMode.NS()
|
|
||||||
if ns == "" {
|
|
||||||
return nil, errors.Errorf("invalid empty user-defined network namespace")
|
|
||||||
}
|
|
||||||
_, err := os.Stat(ns)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
} else if c.NetMode.IsContainer() {
|
|
||||||
connectedCtr, err := runtime.LookupContainer(c.NetMode.Container())
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "container %q not found", c.NetMode.Container())
|
|
||||||
}
|
|
||||||
options = append(options, libpod.WithNetNSFrom(connectedCtr))
|
|
||||||
} else if !c.NetMode.IsHost() && !c.NetMode.IsNone() {
|
|
||||||
hasUserns := c.UsernsMode.IsContainer() || c.UsernsMode.IsNS() || len(c.IDMappings.UIDMap) > 0 || len(c.IDMappings.GIDMap) > 0
|
|
||||||
postConfigureNetNS := hasUserns && !c.UsernsMode.IsHost()
|
|
||||||
options = append(options, libpod.WithNetNS(portBindings, postConfigureNetNS, string(c.NetMode), networks))
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.CgroupMode.IsNS() {
|
|
||||||
ns := c.CgroupMode.NS()
|
|
||||||
if ns == "" {
|
|
||||||
return nil, errors.Errorf("invalid empty user-defined network namespace")
|
|
||||||
}
|
|
||||||
_, err := os.Stat(ns)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
} else if c.CgroupMode.IsContainer() {
|
|
||||||
connectedCtr, err := runtime.LookupContainer(c.CgroupMode.Container())
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "container %q not found", c.CgroupMode.Container())
|
|
||||||
}
|
|
||||||
options = append(options, libpod.WithCgroupNSFrom(connectedCtr))
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.UsernsMode.IsNS() {
|
|
||||||
ns := c.UsernsMode.NS()
|
|
||||||
if ns == "" {
|
|
||||||
return nil, errors.Errorf("invalid empty user-defined user namespace")
|
|
||||||
}
|
|
||||||
_, err := os.Stat(ns)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
options = append(options, libpod.WithIDMappings(*c.IDMappings))
|
|
||||||
} else if c.UsernsMode.IsContainer() {
|
|
||||||
connectedCtr, err := runtime.LookupContainer(c.UsernsMode.Container())
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "container %q not found", c.UsernsMode.Container())
|
|
||||||
}
|
|
||||||
options = append(options, libpod.WithUserNSFrom(connectedCtr))
|
|
||||||
} else {
|
|
||||||
options = append(options, libpod.WithIDMappings(*c.IDMappings))
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.PidMode.IsContainer() {
|
|
||||||
connectedCtr, err := runtime.LookupContainer(c.PidMode.Container())
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "container %q not found", c.PidMode.Container())
|
|
||||||
}
|
|
||||||
|
|
||||||
options = append(options, libpod.WithPIDNSFrom(connectedCtr))
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.IpcMode.IsContainer() {
|
|
||||||
connectedCtr, err := runtime.LookupContainer(c.IpcMode.Container())
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "container %q not found", c.IpcMode.Container())
|
|
||||||
}
|
|
||||||
|
|
||||||
options = append(options, libpod.WithIPCNSFrom(connectedCtr))
|
|
||||||
}
|
|
||||||
|
|
||||||
if IsPod(string(c.UtsMode)) {
|
|
||||||
options = append(options, libpod.WithUTSNSFromPod(pod))
|
|
||||||
}
|
|
||||||
if c.UtsMode.IsContainer() {
|
|
||||||
connectedCtr, err := runtime.LookupContainer(c.UtsMode.Container())
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "container %q not found", c.UtsMode.Container())
|
|
||||||
}
|
|
||||||
|
|
||||||
options = append(options, libpod.WithUTSNSFrom(connectedCtr))
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: MNT, USER, CGROUP
|
// TODO: MNT, USER, CGROUP
|
||||||
options = append(options, libpod.WithStopSignal(c.StopSignal))
|
options = append(options, libpod.WithStopSignal(c.StopSignal))
|
||||||
options = append(options, libpod.WithStopTimeout(c.StopTimeout))
|
options = append(options, libpod.WithStopTimeout(c.StopTimeout))
|
||||||
if len(c.DNSSearch) > 0 {
|
|
||||||
options = append(options, libpod.WithDNSSearch(c.DNSSearch))
|
|
||||||
}
|
|
||||||
if len(c.DNSServers) > 0 {
|
|
||||||
if len(c.DNSServers) == 1 && strings.ToLower(c.DNSServers[0]) == "none" {
|
|
||||||
options = append(options, libpod.WithUseImageResolvConf())
|
|
||||||
} else {
|
|
||||||
options = append(options, libpod.WithDNS(c.DNSServers))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(c.DNSOpt) > 0 {
|
|
||||||
options = append(options, libpod.WithDNSOption(c.DNSOpt))
|
|
||||||
}
|
|
||||||
if c.NoHosts {
|
|
||||||
options = append(options, libpod.WithUseImageHosts())
|
|
||||||
}
|
|
||||||
if len(c.HostAdd) > 0 && !c.NoHosts {
|
|
||||||
options = append(options, libpod.WithHosts(c.HostAdd))
|
|
||||||
}
|
|
||||||
logPath := getLoggingPath(c.LogDriverOpt)
|
logPath := getLoggingPath(c.LogDriverOpt)
|
||||||
if logPath != "" {
|
if logPath != "" {
|
||||||
options = append(options, libpod.WithLogPath(logPath))
|
options = append(options, libpod.WithLogPath(logPath))
|
||||||
@ -386,54 +291,59 @@ func (c *CreateConfig) getContainerCreateOptions(runtime *libpod.Runtime, pod *l
|
|||||||
options = append(options, libpod.WithLogDriver(c.LogDriver))
|
options = append(options, libpod.WithLogDriver(c.LogDriver))
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.IPAddress != "" {
|
secOpts, err := c.Security.ToCreateOptions()
|
||||||
ip := net.ParseIP(c.IPAddress)
|
if err != nil {
|
||||||
if ip == nil {
|
return nil, err
|
||||||
return nil, errors.Wrapf(define.ErrInvalidArg, "cannot parse %s as IP address", c.IPAddress)
|
|
||||||
} else if ip.To4() == nil {
|
|
||||||
return nil, errors.Wrapf(define.ErrInvalidArg, "%s is not an IPv4 address", c.IPAddress)
|
|
||||||
}
|
|
||||||
options = append(options, libpod.WithStaticIP(ip))
|
|
||||||
}
|
}
|
||||||
|
options = append(options, secOpts...)
|
||||||
|
|
||||||
if c.MacAddress != "" {
|
nsOpts, err := c.Cgroup.ToCreateOptions(runtime)
|
||||||
mac, err := net.ParseMAC(c.MacAddress)
|
if err != nil {
|
||||||
if err != nil {
|
return nil, err
|
||||||
return nil, errors.Wrapf(define.ErrInvalidArg, "cannot parse %s as MAC address: %v", c.MacAddress, err)
|
|
||||||
}
|
|
||||||
options = append(options, libpod.WithStaticMAC(mac))
|
|
||||||
}
|
}
|
||||||
|
options = append(options, nsOpts...)
|
||||||
|
|
||||||
options = append(options, libpod.WithPrivileged(c.Privileged))
|
nsOpts, err = c.Ipc.ToCreateOptions(runtime)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
options = append(options, nsOpts...)
|
||||||
|
|
||||||
|
nsOpts, err = c.Pid.ToCreateOptions(runtime)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
options = append(options, nsOpts...)
|
||||||
|
|
||||||
|
nsOpts, err = c.Network.ToCreateOptions(runtime, &c.User)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
options = append(options, nsOpts...)
|
||||||
|
|
||||||
|
nsOpts, err = c.Uts.ToCreateOptions(runtime, pod)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
options = append(options, nsOpts...)
|
||||||
|
|
||||||
|
nsOpts, err = c.User.ToCreateOptions(runtime)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
options = append(options, nsOpts...)
|
||||||
|
|
||||||
useImageVolumes := c.ImageVolumeType == TypeBind
|
useImageVolumes := c.ImageVolumeType == TypeBind
|
||||||
// Gather up the options for NewContainer which consist of With... funcs
|
// Gather up the options for NewContainer which consist of With... funcs
|
||||||
options = append(options, libpod.WithRootFSFromImage(c.ImageID, c.Image, useImageVolumes))
|
options = append(options, libpod.WithRootFSFromImage(c.ImageID, c.Image, useImageVolumes))
|
||||||
options = append(options, libpod.WithSecLabels(c.LabelOpts))
|
|
||||||
options = append(options, libpod.WithConmonPidFile(c.ConmonPidFile))
|
options = append(options, libpod.WithConmonPidFile(c.ConmonPidFile))
|
||||||
options = append(options, libpod.WithLabels(c.Labels))
|
options = append(options, libpod.WithLabels(c.Labels))
|
||||||
options = append(options, libpod.WithUser(c.User))
|
|
||||||
if c.IpcMode.IsHost() {
|
|
||||||
options = append(options, libpod.WithShmDir("/dev/shm"))
|
|
||||||
|
|
||||||
} else if c.IpcMode.IsContainer() {
|
|
||||||
ctr, err := runtime.LookupContainer(c.IpcMode.Container())
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "container %q not found", c.IpcMode.Container())
|
|
||||||
}
|
|
||||||
options = append(options, libpod.WithShmDir(ctr.ShmDir()))
|
|
||||||
}
|
|
||||||
options = append(options, libpod.WithShmSize(c.Resources.ShmSize))
|
options = append(options, libpod.WithShmSize(c.Resources.ShmSize))
|
||||||
options = append(options, libpod.WithGroups(c.GroupAdd))
|
|
||||||
if c.Rootfs != "" {
|
if c.Rootfs != "" {
|
||||||
options = append(options, libpod.WithRootFS(c.Rootfs))
|
options = append(options, libpod.WithRootFS(c.Rootfs))
|
||||||
}
|
}
|
||||||
// Default used if not overridden on command line
|
// Default used if not overridden on command line
|
||||||
|
|
||||||
if c.CgroupParent != "" {
|
|
||||||
options = append(options, libpod.WithCgroupParent(c.CgroupParent))
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.RestartPolicy != "" {
|
if c.RestartPolicy != "" {
|
||||||
if c.RestartPolicy == "unless-stopped" {
|
if c.RestartPolicy == "unless-stopped" {
|
||||||
return nil, errors.Wrapf(define.ErrInvalidArg, "the unless-stopped restart policy is not supported")
|
return nil, errors.Wrapf(define.ErrInvalidArg, "the unless-stopped restart policy is not supported")
|
||||||
@ -467,38 +377,6 @@ func (c *CreateConfig) getContainerCreateOptions(runtime *libpod.Runtime, pod *l
|
|||||||
return options, nil
|
return options, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatePortBindings iterates ports mappings and exposed ports into a format CNI understands
|
|
||||||
func (c *CreateConfig) CreatePortBindings() ([]ocicni.PortMapping, error) {
|
|
||||||
return NatToOCIPortBindings(c.PortBindings)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NatToOCIPortBindings iterates a nat.portmap slice and creates []ocicni portmapping slice
|
|
||||||
func NatToOCIPortBindings(ports nat.PortMap) ([]ocicni.PortMapping, error) {
|
|
||||||
var portBindings []ocicni.PortMapping
|
|
||||||
for containerPb, hostPb := range ports {
|
|
||||||
var pm ocicni.PortMapping
|
|
||||||
pm.ContainerPort = int32(containerPb.Int())
|
|
||||||
for _, i := range hostPb {
|
|
||||||
var hostPort int
|
|
||||||
var err error
|
|
||||||
pm.HostIP = i.HostIP
|
|
||||||
if i.HostPort == "" {
|
|
||||||
hostPort = containerPb.Int()
|
|
||||||
} else {
|
|
||||||
hostPort, err = strconv.Atoi(i.HostPort)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "unable to convert host port to integer")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pm.HostPort = int32(hostPort)
|
|
||||||
pm.Protocol = containerPb.Proto()
|
|
||||||
portBindings = append(portBindings, pm)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return portBindings, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddPrivilegedDevices iterates through host devices and adds all
|
// AddPrivilegedDevices iterates through host devices and adds all
|
||||||
// host devices to the spec
|
// host devices to the spec
|
||||||
func (c *CreateConfig) AddPrivilegedDevices(g *generate.Generator) error {
|
func (c *CreateConfig) AddPrivilegedDevices(g *generate.Generator) error {
|
||||||
|
433
pkg/spec/namespaces.go
Normal file
433
pkg/spec/namespaces.go
Normal file
@ -0,0 +1,433 @@
|
|||||||
|
package createconfig
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/containers/libpod/libpod"
|
||||||
|
"github.com/containers/libpod/libpod/define"
|
||||||
|
"github.com/containers/libpod/pkg/cgroups"
|
||||||
|
"github.com/cri-o/ocicni/pkg/ocicni"
|
||||||
|
"github.com/docker/go-connections/nat"
|
||||||
|
spec "github.com/opencontainers/runtime-spec/specs-go"
|
||||||
|
"github.com/opencontainers/runtime-tools/generate"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *NetworkConfig) ToCreateOptions(runtime *libpod.Runtime, userns *UserConfig) ([]libpod.CtrCreateOption, error) {
|
||||||
|
var portBindings []ocicni.PortMapping
|
||||||
|
var err error
|
||||||
|
if len(c.PortBindings) > 0 {
|
||||||
|
portBindings, err = NatToOCIPortBindings(c.PortBindings)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "unable to create port bindings")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
options := make([]libpod.CtrCreateOption, 0)
|
||||||
|
userNetworks := c.NetMode.UserDefined()
|
||||||
|
networks := make([]string, 0)
|
||||||
|
|
||||||
|
if IsPod(userNetworks) {
|
||||||
|
userNetworks = ""
|
||||||
|
}
|
||||||
|
if userNetworks != "" {
|
||||||
|
for _, netName := range strings.Split(userNetworks, ",") {
|
||||||
|
if netName == "" {
|
||||||
|
return nil, errors.Errorf("container networks %q invalid", userNetworks)
|
||||||
|
}
|
||||||
|
networks = append(networks, netName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.NetMode.IsNS() {
|
||||||
|
ns := c.NetMode.NS()
|
||||||
|
if ns == "" {
|
||||||
|
return nil, errors.Errorf("invalid empty user-defined network namespace")
|
||||||
|
}
|
||||||
|
_, err := os.Stat(ns)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
} else if c.NetMode.IsContainer() {
|
||||||
|
connectedCtr, err := runtime.LookupContainer(c.NetMode.Container())
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "container %q not found", c.NetMode.Container())
|
||||||
|
}
|
||||||
|
options = append(options, libpod.WithNetNSFrom(connectedCtr))
|
||||||
|
} else if !c.NetMode.IsHost() && !c.NetMode.IsNone() {
|
||||||
|
postConfigureNetNS := userns.getPostConfigureNetNS()
|
||||||
|
options = append(options, libpod.WithNetNS(portBindings, postConfigureNetNS, string(c.NetMode), networks))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(c.DNSSearch) > 0 {
|
||||||
|
options = append(options, libpod.WithDNSSearch(c.DNSSearch))
|
||||||
|
}
|
||||||
|
if len(c.DNSServers) > 0 {
|
||||||
|
if len(c.DNSServers) == 1 && strings.ToLower(c.DNSServers[0]) == "none" {
|
||||||
|
options = append(options, libpod.WithUseImageResolvConf())
|
||||||
|
} else {
|
||||||
|
options = append(options, libpod.WithDNS(c.DNSServers))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(c.DNSOpt) > 0 {
|
||||||
|
options = append(options, libpod.WithDNSOption(c.DNSOpt))
|
||||||
|
}
|
||||||
|
if c.IPAddress != "" {
|
||||||
|
ip := net.ParseIP(c.IPAddress)
|
||||||
|
if ip == nil {
|
||||||
|
return nil, errors.Wrapf(define.ErrInvalidArg, "cannot parse %s as IP address", c.IPAddress)
|
||||||
|
} else if ip.To4() == nil {
|
||||||
|
return nil, errors.Wrapf(define.ErrInvalidArg, "%s is not an IPv4 address", c.IPAddress)
|
||||||
|
}
|
||||||
|
options = append(options, libpod.WithStaticIP(ip))
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.MacAddress != "" {
|
||||||
|
mac, err := net.ParseMAC(c.MacAddress)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(define.ErrInvalidArg, "cannot parse %s as MAC address: %v", c.MacAddress, err)
|
||||||
|
}
|
||||||
|
options = append(options, libpod.WithStaticMAC(mac))
|
||||||
|
}
|
||||||
|
|
||||||
|
return options, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *NetworkConfig) ConfigureGenerator(g *generate.Generator) error {
|
||||||
|
netMode := c.NetMode
|
||||||
|
if netMode.IsHost() {
|
||||||
|
logrus.Debug("Using host netmode")
|
||||||
|
if err := g.RemoveLinuxNamespace(string(spec.NetworkNamespace)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else if netMode.IsNone() {
|
||||||
|
logrus.Debug("Using none netmode")
|
||||||
|
} else if netMode.IsBridge() {
|
||||||
|
logrus.Debug("Using bridge netmode")
|
||||||
|
} else if netCtr := netMode.Container(); netCtr != "" {
|
||||||
|
logrus.Debugf("using container %s netmode", netCtr)
|
||||||
|
} else if IsNS(string(netMode)) {
|
||||||
|
logrus.Debug("Using ns netmode")
|
||||||
|
if err := g.AddOrReplaceLinuxNamespace(string(spec.NetworkNamespace), NS(string(netMode))); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else if IsPod(string(netMode)) {
|
||||||
|
logrus.Debug("Using pod netmode, unless pod is not sharing")
|
||||||
|
} else if netMode.IsSlirp4netns() {
|
||||||
|
logrus.Debug("Using slirp4netns netmode")
|
||||||
|
} else if netMode.IsUserDefined() {
|
||||||
|
logrus.Debug("Using user defined netmode")
|
||||||
|
} else {
|
||||||
|
return errors.Errorf("unknown network mode")
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.HTTPProxy {
|
||||||
|
for _, envSpec := range []string{
|
||||||
|
"http_proxy",
|
||||||
|
"HTTP_PROXY",
|
||||||
|
"https_proxy",
|
||||||
|
"HTTPS_PROXY",
|
||||||
|
"ftp_proxy",
|
||||||
|
"FTP_PROXY",
|
||||||
|
"no_proxy",
|
||||||
|
"NO_PROXY",
|
||||||
|
} {
|
||||||
|
envVal := os.Getenv(envSpec)
|
||||||
|
if envVal != "" {
|
||||||
|
g.AddProcessEnv(envSpec, envVal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if g.Config.Annotations == nil {
|
||||||
|
g.Config.Annotations = make(map[string]string)
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.PublishAll {
|
||||||
|
g.Config.Annotations[libpod.InspectAnnotationPublishAll] = libpod.InspectResponseTrue
|
||||||
|
} else {
|
||||||
|
g.Config.Annotations[libpod.InspectAnnotationPublishAll] = libpod.InspectResponseFalse
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NatToOCIPortBindings iterates a nat.portmap slice and creates []ocicni portmapping slice
|
||||||
|
func NatToOCIPortBindings(ports nat.PortMap) ([]ocicni.PortMapping, error) {
|
||||||
|
var portBindings []ocicni.PortMapping
|
||||||
|
for containerPb, hostPb := range ports {
|
||||||
|
var pm ocicni.PortMapping
|
||||||
|
pm.ContainerPort = int32(containerPb.Int())
|
||||||
|
for _, i := range hostPb {
|
||||||
|
var hostPort int
|
||||||
|
var err error
|
||||||
|
pm.HostIP = i.HostIP
|
||||||
|
if i.HostPort == "" {
|
||||||
|
hostPort = containerPb.Int()
|
||||||
|
} else {
|
||||||
|
hostPort, err = strconv.Atoi(i.HostPort)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "unable to convert host port to integer")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pm.HostPort = int32(hostPort)
|
||||||
|
pm.Protocol = containerPb.Proto()
|
||||||
|
portBindings = append(portBindings, pm)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return portBindings, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CgroupConfig) ToCreateOptions(runtime *libpod.Runtime) ([]libpod.CtrCreateOption, error) {
|
||||||
|
options := make([]libpod.CtrCreateOption, 0)
|
||||||
|
if c.CgroupMode.IsNS() {
|
||||||
|
ns := c.CgroupMode.NS()
|
||||||
|
if ns == "" {
|
||||||
|
return nil, errors.Errorf("invalid empty user-defined network namespace")
|
||||||
|
}
|
||||||
|
_, err := os.Stat(ns)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
} else if c.CgroupMode.IsContainer() {
|
||||||
|
connectedCtr, err := runtime.LookupContainer(c.CgroupMode.Container())
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "container %q not found", c.CgroupMode.Container())
|
||||||
|
}
|
||||||
|
options = append(options, libpod.WithCgroupNSFrom(connectedCtr))
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.CgroupParent != "" {
|
||||||
|
options = append(options, libpod.WithCgroupParent(c.CgroupParent))
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Cgroups == "disabled" {
|
||||||
|
options = append(options, libpod.WithNoCgroups())
|
||||||
|
}
|
||||||
|
|
||||||
|
return options, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *UserConfig) ToCreateOptions(runtime *libpod.Runtime) ([]libpod.CtrCreateOption, error) {
|
||||||
|
options := make([]libpod.CtrCreateOption, 0)
|
||||||
|
if c.UsernsMode.IsNS() {
|
||||||
|
ns := c.UsernsMode.NS()
|
||||||
|
if ns == "" {
|
||||||
|
return nil, errors.Errorf("invalid empty user-defined user namespace")
|
||||||
|
}
|
||||||
|
_, err := os.Stat(ns)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
options = append(options, libpod.WithIDMappings(*c.IDMappings))
|
||||||
|
} else if c.UsernsMode.IsContainer() {
|
||||||
|
connectedCtr, err := runtime.LookupContainer(c.UsernsMode.Container())
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "container %q not found", c.UsernsMode.Container())
|
||||||
|
}
|
||||||
|
options = append(options, libpod.WithUserNSFrom(connectedCtr))
|
||||||
|
} else {
|
||||||
|
options = append(options, libpod.WithIDMappings(*c.IDMappings))
|
||||||
|
}
|
||||||
|
|
||||||
|
options = append(options, libpod.WithUser(c.User))
|
||||||
|
options = append(options, libpod.WithGroups(c.GroupAdd))
|
||||||
|
|
||||||
|
return options, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *UserConfig) ConfigureGenerator(g *generate.Generator) error {
|
||||||
|
if IsNS(string(c.UsernsMode)) {
|
||||||
|
if err := g.AddOrReplaceLinuxNamespace(string(spec.UserNamespace), NS(string(c.UsernsMode))); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// runc complains if no mapping is specified, even if we join another ns. So provide a dummy mapping
|
||||||
|
g.AddLinuxUIDMapping(uint32(0), uint32(0), uint32(1))
|
||||||
|
g.AddLinuxGIDMapping(uint32(0), uint32(0), uint32(1))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len(c.IDMappings.UIDMap) > 0 || len(c.IDMappings.GIDMap) > 0) && !c.UsernsMode.IsHost() {
|
||||||
|
if err := g.AddOrReplaceLinuxNamespace(string(spec.UserNamespace), ""); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, uidmap := range c.IDMappings.UIDMap {
|
||||||
|
g.AddLinuxUIDMapping(uint32(uidmap.HostID), uint32(uidmap.ContainerID), uint32(uidmap.Size))
|
||||||
|
}
|
||||||
|
for _, gidmap := range c.IDMappings.GIDMap {
|
||||||
|
g.AddLinuxGIDMapping(uint32(gidmap.HostID), uint32(gidmap.ContainerID), uint32(gidmap.Size))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *UserConfig) getPostConfigureNetNS() bool {
|
||||||
|
hasUserns := c.UsernsMode.IsContainer() || c.UsernsMode.IsNS() || len(c.IDMappings.UIDMap) > 0 || len(c.IDMappings.GIDMap) > 0
|
||||||
|
postConfigureNetNS := hasUserns && !c.UsernsMode.IsHost()
|
||||||
|
return postConfigureNetNS
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *UserConfig) InNS(isRootless bool) bool {
|
||||||
|
hasUserns := c.UsernsMode.IsContainer() || c.UsernsMode.IsNS() || len(c.IDMappings.UIDMap) > 0 || len(c.IDMappings.GIDMap) > 0
|
||||||
|
return isRootless || (hasUserns && !c.UsernsMode.IsHost())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *IpcConfig) ToCreateOptions(runtime *libpod.Runtime) ([]libpod.CtrCreateOption, error) {
|
||||||
|
options := make([]libpod.CtrCreateOption, 0)
|
||||||
|
if c.IpcMode.IsHost() {
|
||||||
|
options = append(options, libpod.WithShmDir("/dev/shm"))
|
||||||
|
} else if c.IpcMode.IsContainer() {
|
||||||
|
connectedCtr, err := runtime.LookupContainer(c.IpcMode.Container())
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "container %q not found", c.IpcMode.Container())
|
||||||
|
}
|
||||||
|
|
||||||
|
options = append(options, libpod.WithIPCNSFrom(connectedCtr))
|
||||||
|
options = append(options, libpod.WithShmDir(connectedCtr.ShmDir()))
|
||||||
|
}
|
||||||
|
|
||||||
|
return options, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *IpcConfig) ConfigureGenerator(g *generate.Generator) error {
|
||||||
|
ipcMode := c.IpcMode
|
||||||
|
if IsNS(string(ipcMode)) {
|
||||||
|
return g.AddOrReplaceLinuxNamespace(string(spec.IPCNamespace), NS(string(ipcMode)))
|
||||||
|
}
|
||||||
|
if ipcMode.IsHost() {
|
||||||
|
return g.RemoveLinuxNamespace(string(spec.IPCNamespace))
|
||||||
|
}
|
||||||
|
if ipcCtr := ipcMode.Container(); ipcCtr != "" {
|
||||||
|
logrus.Debugf("Using container %s ipcmode", ipcCtr)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CgroupConfig) ConfigureGenerator(g *generate.Generator) error {
|
||||||
|
cgroupMode := c.CgroupMode
|
||||||
|
if cgroupMode.IsDefaultValue() {
|
||||||
|
// If the value is not specified, default to "private" on cgroups v2 and "host" on cgroups v1.
|
||||||
|
unified, err := cgroups.IsCgroup2UnifiedMode()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if unified {
|
||||||
|
cgroupMode = "private"
|
||||||
|
} else {
|
||||||
|
cgroupMode = "host"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if cgroupMode.IsNS() {
|
||||||
|
return g.AddOrReplaceLinuxNamespace(string(spec.CgroupNamespace), NS(string(cgroupMode)))
|
||||||
|
}
|
||||||
|
if cgroupMode.IsHost() {
|
||||||
|
return g.RemoveLinuxNamespace(string(spec.CgroupNamespace))
|
||||||
|
}
|
||||||
|
if cgroupMode.IsPrivate() {
|
||||||
|
return g.AddOrReplaceLinuxNamespace(string(spec.CgroupNamespace), "")
|
||||||
|
}
|
||||||
|
if cgCtr := cgroupMode.Container(); cgCtr != "" {
|
||||||
|
logrus.Debugf("Using container %s cgroup mode", cgCtr)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *PidConfig) ToCreateOptions(runtime *libpod.Runtime) ([]libpod.CtrCreateOption, error) {
|
||||||
|
options := make([]libpod.CtrCreateOption, 0)
|
||||||
|
if c.PidMode.IsContainer() {
|
||||||
|
connectedCtr, err := runtime.LookupContainer(c.PidMode.Container())
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "container %q not found", c.PidMode.Container())
|
||||||
|
}
|
||||||
|
|
||||||
|
options = append(options, libpod.WithPIDNSFrom(connectedCtr))
|
||||||
|
}
|
||||||
|
|
||||||
|
return options, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *PidConfig) ConfigureGenerator(g *generate.Generator) error {
|
||||||
|
pidMode := c.PidMode
|
||||||
|
if IsNS(string(pidMode)) {
|
||||||
|
return g.AddOrReplaceLinuxNamespace(string(spec.PIDNamespace), NS(string(pidMode)))
|
||||||
|
}
|
||||||
|
if pidMode.IsHost() {
|
||||||
|
return g.RemoveLinuxNamespace(string(spec.PIDNamespace))
|
||||||
|
}
|
||||||
|
if pidCtr := pidMode.Container(); pidCtr != "" {
|
||||||
|
logrus.Debugf("using container %s pidmode", pidCtr)
|
||||||
|
}
|
||||||
|
if IsPod(string(pidMode)) {
|
||||||
|
logrus.Debug("using pod pidmode")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *UtsConfig) ToCreateOptions(runtime *libpod.Runtime, pod *libpod.Pod) ([]libpod.CtrCreateOption, error) {
|
||||||
|
options := make([]libpod.CtrCreateOption, 0)
|
||||||
|
if IsPod(string(c.UtsMode)) {
|
||||||
|
options = append(options, libpod.WithUTSNSFromPod(pod))
|
||||||
|
}
|
||||||
|
if c.UtsMode.IsContainer() {
|
||||||
|
connectedCtr, err := runtime.LookupContainer(c.UtsMode.Container())
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "container %q not found", c.UtsMode.Container())
|
||||||
|
}
|
||||||
|
|
||||||
|
options = append(options, libpod.WithUTSNSFrom(connectedCtr))
|
||||||
|
}
|
||||||
|
if c.NoHosts {
|
||||||
|
options = append(options, libpod.WithUseImageHosts())
|
||||||
|
}
|
||||||
|
if len(c.HostAdd) > 0 && !c.NoHosts {
|
||||||
|
options = append(options, libpod.WithHosts(c.HostAdd))
|
||||||
|
}
|
||||||
|
|
||||||
|
return options, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *UtsConfig) ConfigureGenerator(g *generate.Generator, net *NetworkConfig, runtime *libpod.Runtime) error {
|
||||||
|
hostname := c.Hostname
|
||||||
|
var err error
|
||||||
|
if hostname == "" {
|
||||||
|
if utsCtrID := c.UtsMode.Container(); utsCtrID != "" {
|
||||||
|
utsCtr, err := runtime.GetContainer(utsCtrID)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "unable to retrieve hostname from dependency container %s", utsCtrID)
|
||||||
|
}
|
||||||
|
hostname = utsCtr.Hostname()
|
||||||
|
} else if net.NetMode.IsHost() || c.UtsMode.IsHost() {
|
||||||
|
hostname, err = os.Hostname()
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "unable to retrieve hostname of the host")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logrus.Debug("No hostname set; container's hostname will default to runtime default")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g.RemoveHostname()
|
||||||
|
if c.Hostname != "" || !c.UtsMode.IsHost() {
|
||||||
|
// Set the hostname in the OCI configuration only
|
||||||
|
// if specified by the user or if we are creating
|
||||||
|
// a new UTS namespace.
|
||||||
|
g.SetHostname(hostname)
|
||||||
|
}
|
||||||
|
g.AddProcessEnv("HOSTNAME", hostname)
|
||||||
|
|
||||||
|
utsMode := c.UtsMode
|
||||||
|
if IsNS(string(utsMode)) {
|
||||||
|
return g.AddOrReplaceLinuxNamespace(string(spec.UTSNamespace), NS(string(utsMode)))
|
||||||
|
}
|
||||||
|
if utsMode.IsHost() {
|
||||||
|
return g.RemoveLinuxNamespace(string(spec.UTSNamespace))
|
||||||
|
}
|
||||||
|
if utsCtr := utsMode.Container(); utsCtr != "" {
|
||||||
|
logrus.Debugf("using container %s utsmode", utsCtr)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
172
pkg/spec/security.go
Normal file
172
pkg/spec/security.go
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
package createconfig
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/containers/libpod/libpod"
|
||||||
|
"github.com/docker/docker/oci/caps"
|
||||||
|
"github.com/opencontainers/runtime-tools/generate"
|
||||||
|
"github.com/opencontainers/selinux/go-selinux/label"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *SecurityConfig) ToCreateOptions() ([]libpod.CtrCreateOption, error) {
|
||||||
|
options := make([]libpod.CtrCreateOption, 0)
|
||||||
|
options = append(options, libpod.WithSecLabels(c.LabelOpts))
|
||||||
|
options = append(options, libpod.WithPrivileged(c.Privileged))
|
||||||
|
return options, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *SecurityConfig) SetLabelOpts(runtime *libpod.Runtime, pidConfig *PidConfig, ipcConfig *IpcConfig) error {
|
||||||
|
if c.Privileged {
|
||||||
|
c.LabelOpts = label.DisableSecOpt()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var labelOpts []string
|
||||||
|
if pidConfig.PidMode.IsHost() {
|
||||||
|
labelOpts = append(labelOpts, label.DisableSecOpt()...)
|
||||||
|
} else if pidConfig.PidMode.IsContainer() {
|
||||||
|
ctr, err := runtime.LookupContainer(pidConfig.PidMode.Container())
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "container %q not found", pidConfig.PidMode.Container())
|
||||||
|
}
|
||||||
|
secopts, err := label.DupSecOpt(ctr.ProcessLabel())
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to duplicate label %q ", ctr.ProcessLabel())
|
||||||
|
}
|
||||||
|
labelOpts = append(labelOpts, secopts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ipcConfig.IpcMode.IsHost() {
|
||||||
|
labelOpts = append(labelOpts, label.DisableSecOpt()...)
|
||||||
|
} else if ipcConfig.IpcMode.IsContainer() {
|
||||||
|
ctr, err := runtime.LookupContainer(ipcConfig.IpcMode.Container())
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "container %q not found", ipcConfig.IpcMode.Container())
|
||||||
|
}
|
||||||
|
secopts, err := label.DupSecOpt(ctr.ProcessLabel())
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to duplicate label %q ", ctr.ProcessLabel())
|
||||||
|
}
|
||||||
|
labelOpts = append(labelOpts, secopts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.LabelOpts = append(c.LabelOpts, labelOpts...)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *SecurityConfig) SetSecurityOpts(runtime *libpod.Runtime, securityOpts []string) error {
|
||||||
|
for _, opt := range securityOpts {
|
||||||
|
if opt == "no-new-privileges" {
|
||||||
|
c.NoNewPrivs = true
|
||||||
|
} else {
|
||||||
|
con := strings.SplitN(opt, "=", 2)
|
||||||
|
if len(con) != 2 {
|
||||||
|
return fmt.Errorf("invalid --security-opt 1: %q", opt)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch con[0] {
|
||||||
|
case "label":
|
||||||
|
c.LabelOpts = append(c.LabelOpts, con[1])
|
||||||
|
case "apparmor":
|
||||||
|
c.ApparmorProfile = con[1]
|
||||||
|
case "seccomp":
|
||||||
|
c.SeccompProfilePath = con[1]
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("invalid --security-opt 2: %q", opt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.SeccompProfilePath == "" {
|
||||||
|
var err error
|
||||||
|
c.SeccompProfilePath, err = libpod.DefaultSeccompPath()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.SecurityOpts = securityOpts
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *SecurityConfig) ConfigureGenerator(g *generate.Generator, user *UserConfig) error {
|
||||||
|
// HANDLE CAPABILITIES
|
||||||
|
// NOTE: Must happen before SECCOMP
|
||||||
|
if c.Privileged {
|
||||||
|
g.SetupPrivileged(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
useNotRoot := func(user string) bool {
|
||||||
|
if user == "" || user == "root" || user == "0" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
configSpec := g.Config
|
||||||
|
var err error
|
||||||
|
var caplist []string
|
||||||
|
bounding := configSpec.Process.Capabilities.Bounding
|
||||||
|
if useNotRoot(user.User) {
|
||||||
|
configSpec.Process.Capabilities.Bounding = caplist
|
||||||
|
}
|
||||||
|
caplist, err = caps.TweakCapabilities(configSpec.Process.Capabilities.Bounding, c.CapAdd, c.CapDrop, nil, false)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
configSpec.Process.Capabilities.Bounding = caplist
|
||||||
|
configSpec.Process.Capabilities.Permitted = caplist
|
||||||
|
configSpec.Process.Capabilities.Inheritable = caplist
|
||||||
|
configSpec.Process.Capabilities.Effective = caplist
|
||||||
|
configSpec.Process.Capabilities.Ambient = caplist
|
||||||
|
if useNotRoot(user.User) {
|
||||||
|
caplist, err = caps.TweakCapabilities(bounding, c.CapAdd, c.CapDrop, nil, false)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
configSpec.Process.Capabilities.Bounding = caplist
|
||||||
|
|
||||||
|
// HANDLE SECCOMP
|
||||||
|
if c.SeccompProfilePath != "unconfined" {
|
||||||
|
seccompConfig, err := getSeccompConfig(c, configSpec)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
configSpec.Linux.Seccomp = seccompConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear default Seccomp profile from Generator for privileged containers
|
||||||
|
if c.SeccompProfilePath == "unconfined" || c.Privileged {
|
||||||
|
configSpec.Linux.Seccomp = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, opt := range c.SecurityOpts {
|
||||||
|
// Split on both : and =
|
||||||
|
splitOpt := strings.Split(opt, "=")
|
||||||
|
if len(splitOpt) == 1 {
|
||||||
|
splitOpt = strings.Split(opt, ":")
|
||||||
|
}
|
||||||
|
if len(splitOpt) < 2 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
switch splitOpt[0] {
|
||||||
|
case "label":
|
||||||
|
configSpec.Annotations[libpod.InspectAnnotationLabel] = splitOpt[1]
|
||||||
|
case "seccomp":
|
||||||
|
configSpec.Annotations[libpod.InspectAnnotationSeccomp] = splitOpt[1]
|
||||||
|
case "apparmor":
|
||||||
|
configSpec.Annotations[libpod.InspectAnnotationApparmor] = splitOpt[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g.SetRootReadonly(c.ReadOnlyRootfs)
|
||||||
|
for sysctlKey, sysctlVal := range c.Sysctl {
|
||||||
|
g.AddLinuxSysctl(sysctlKey, sysctlVal)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
315
pkg/spec/spec.go
315
pkg/spec/spec.go
@ -1,7 +1,6 @@
|
|||||||
package createconfig
|
package createconfig
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/containers/libpod/libpod"
|
"github.com/containers/libpod/libpod"
|
||||||
@ -10,13 +9,11 @@ import (
|
|||||||
"github.com/containers/libpod/pkg/cgroups"
|
"github.com/containers/libpod/pkg/cgroups"
|
||||||
"github.com/containers/libpod/pkg/rootless"
|
"github.com/containers/libpod/pkg/rootless"
|
||||||
"github.com/containers/libpod/pkg/sysinfo"
|
"github.com/containers/libpod/pkg/sysinfo"
|
||||||
"github.com/docker/docker/oci/caps"
|
|
||||||
"github.com/docker/go-units"
|
"github.com/docker/go-units"
|
||||||
"github.com/opencontainers/runc/libcontainer/user"
|
"github.com/opencontainers/runc/libcontainer/user"
|
||||||
spec "github.com/opencontainers/runtime-spec/specs-go"
|
spec "github.com/opencontainers/runtime-spec/specs-go"
|
||||||
"github.com/opencontainers/runtime-tools/generate"
|
"github.com/opencontainers/runtime-tools/generate"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const cpuPeriod = 100000
|
const cpuPeriod = 100000
|
||||||
@ -47,14 +44,13 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM
|
|||||||
canMountSys := true
|
canMountSys := true
|
||||||
|
|
||||||
isRootless := rootless.IsRootless()
|
isRootless := rootless.IsRootless()
|
||||||
hasUserns := config.UsernsMode.IsContainer() || config.UsernsMode.IsNS() || len(config.IDMappings.UIDMap) > 0 || len(config.IDMappings.GIDMap) > 0
|
inUserNS := config.User.InNS(isRootless)
|
||||||
inUserNS := isRootless || (hasUserns && !config.UsernsMode.IsHost())
|
|
||||||
|
|
||||||
if inUserNS && config.NetMode.IsHost() {
|
if inUserNS && config.Network.NetMode.IsHost() {
|
||||||
canMountSys = false
|
canMountSys = false
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.Privileged && canMountSys {
|
if config.Security.Privileged && canMountSys {
|
||||||
cgroupPerm = "rw"
|
cgroupPerm = "rw"
|
||||||
g.RemoveMount("/sys")
|
g.RemoveMount("/sys")
|
||||||
sysMnt := spec.Mount{
|
sysMnt := spec.Mount{
|
||||||
@ -68,7 +64,7 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM
|
|||||||
addCgroup = false
|
addCgroup = false
|
||||||
g.RemoveMount("/sys")
|
g.RemoveMount("/sys")
|
||||||
r := "ro"
|
r := "ro"
|
||||||
if config.Privileged {
|
if config.Security.Privileged {
|
||||||
r = "rw"
|
r = "rw"
|
||||||
}
|
}
|
||||||
sysMnt := spec.Mount{
|
sysMnt := spec.Mount{
|
||||||
@ -78,7 +74,7 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM
|
|||||||
Options: []string{"rprivate", "nosuid", "noexec", "nodev", r, "rbind"},
|
Options: []string{"rprivate", "nosuid", "noexec", "nodev", r, "rbind"},
|
||||||
}
|
}
|
||||||
g.AddMount(sysMnt)
|
g.AddMount(sysMnt)
|
||||||
if !config.Privileged && isRootless {
|
if !config.Security.Privileged && isRootless {
|
||||||
g.AddLinuxMaskedPaths("/sys/kernel")
|
g.AddLinuxMaskedPaths("/sys/kernel")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -92,9 +88,9 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM
|
|||||||
}
|
}
|
||||||
// When using a different user namespace, check that the GID 5 is mapped inside
|
// When using a different user namespace, check that the GID 5 is mapped inside
|
||||||
// the container.
|
// the container.
|
||||||
if gid5Available && len(config.IDMappings.GIDMap) > 0 {
|
if gid5Available && len(config.User.IDMappings.GIDMap) > 0 {
|
||||||
mappingFound := false
|
mappingFound := false
|
||||||
for _, r := range config.IDMappings.GIDMap {
|
for _, r := range config.User.IDMappings.GIDMap {
|
||||||
if r.ContainerID <= 5 && 5 < r.ContainerID+r.Size {
|
if r.ContainerID <= 5 && 5 < r.ContainerID+r.Size {
|
||||||
mappingFound = true
|
mappingFound = true
|
||||||
break
|
break
|
||||||
@ -117,7 +113,7 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM
|
|||||||
g.AddMount(devPts)
|
g.AddMount(devPts)
|
||||||
}
|
}
|
||||||
|
|
||||||
if inUserNS && config.IpcMode.IsHost() {
|
if inUserNS && config.Ipc.IpcMode.IsHost() {
|
||||||
g.RemoveMount("/dev/mqueue")
|
g.RemoveMount("/dev/mqueue")
|
||||||
devMqueue := spec.Mount{
|
devMqueue := spec.Mount{
|
||||||
Destination: "/dev/mqueue",
|
Destination: "/dev/mqueue",
|
||||||
@ -127,7 +123,7 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM
|
|||||||
}
|
}
|
||||||
g.AddMount(devMqueue)
|
g.AddMount(devMqueue)
|
||||||
}
|
}
|
||||||
if inUserNS && config.PidMode.IsHost() {
|
if inUserNS && config.Pid.PidMode.IsHost() {
|
||||||
g.RemoveMount("/proc")
|
g.RemoveMount("/proc")
|
||||||
procMount := spec.Mount{
|
procMount := spec.Mount{
|
||||||
Destination: "/proc",
|
Destination: "/proc",
|
||||||
@ -154,55 +150,6 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM
|
|||||||
for key, val := range config.Annotations {
|
for key, val := range config.Annotations {
|
||||||
g.AddAnnotation(key, val)
|
g.AddAnnotation(key, val)
|
||||||
}
|
}
|
||||||
g.SetRootReadonly(config.ReadOnlyRootfs)
|
|
||||||
|
|
||||||
if config.HTTPProxy {
|
|
||||||
for _, envSpec := range []string{
|
|
||||||
"http_proxy",
|
|
||||||
"HTTP_PROXY",
|
|
||||||
"https_proxy",
|
|
||||||
"HTTPS_PROXY",
|
|
||||||
"ftp_proxy",
|
|
||||||
"FTP_PROXY",
|
|
||||||
"no_proxy",
|
|
||||||
"NO_PROXY",
|
|
||||||
} {
|
|
||||||
envVal := os.Getenv(envSpec)
|
|
||||||
if envVal != "" {
|
|
||||||
g.AddProcessEnv(envSpec, envVal)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hostname := config.Hostname
|
|
||||||
if hostname == "" {
|
|
||||||
if utsCtrID := config.UtsMode.Container(); utsCtrID != "" {
|
|
||||||
utsCtr, err := runtime.GetContainer(utsCtrID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "unable to retrieve hostname from dependency container %s", utsCtrID)
|
|
||||||
}
|
|
||||||
hostname = utsCtr.Hostname()
|
|
||||||
} else if config.NetMode.IsHost() || config.UtsMode.IsHost() {
|
|
||||||
hostname, err = os.Hostname()
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "unable to retrieve hostname of the host")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
logrus.Debug("No hostname set; container's hostname will default to runtime default")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
g.RemoveHostname()
|
|
||||||
if config.Hostname != "" || !config.UtsMode.IsHost() {
|
|
||||||
// Set the hostname in the OCI configuration only
|
|
||||||
// if specified by the user or if we are creating
|
|
||||||
// a new UTS namespace.
|
|
||||||
g.SetHostname(hostname)
|
|
||||||
}
|
|
||||||
g.AddProcessEnv("HOSTNAME", hostname)
|
|
||||||
|
|
||||||
for sysctlKey, sysctlVal := range config.Sysctl {
|
|
||||||
g.AddLinuxSysctl(sysctlKey, sysctlVal)
|
|
||||||
}
|
|
||||||
g.AddProcessEnv("container", "podman")
|
g.AddProcessEnv("container", "podman")
|
||||||
|
|
||||||
addedResources := false
|
addedResources := false
|
||||||
@ -272,7 +219,7 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Devices
|
// Devices
|
||||||
if config.Privileged {
|
if config.Security.Privileged {
|
||||||
// If privileged, we need to add all the host devices to the
|
// If privileged, we need to add all the host devices to the
|
||||||
// spec. We do not add the user provided ones because we are
|
// spec. We do not add the user provided ones because we are
|
||||||
// already adding them all.
|
// already adding them all.
|
||||||
@ -287,17 +234,11 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, uidmap := range config.IDMappings.UIDMap {
|
|
||||||
g.AddLinuxUIDMapping(uint32(uidmap.HostID), uint32(uidmap.ContainerID), uint32(uidmap.Size))
|
|
||||||
}
|
|
||||||
for _, gidmap := range config.IDMappings.GIDMap {
|
|
||||||
g.AddLinuxGIDMapping(uint32(gidmap.HostID), uint32(gidmap.ContainerID), uint32(gidmap.Size))
|
|
||||||
}
|
|
||||||
// SECURITY OPTS
|
// SECURITY OPTS
|
||||||
g.SetProcessNoNewPrivileges(config.NoNewPrivs)
|
g.SetProcessNoNewPrivileges(config.Security.NoNewPrivs)
|
||||||
|
|
||||||
if !config.Privileged {
|
if !config.Security.Privileged {
|
||||||
g.SetProcessApparmorProfile(config.ApparmorProfile)
|
g.SetProcessApparmorProfile(config.Security.ApparmorProfile)
|
||||||
}
|
}
|
||||||
|
|
||||||
blockAccessToKernelFilesystems(config, &g)
|
blockAccessToKernelFilesystems(config, &g)
|
||||||
@ -341,54 +282,35 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := addPidNS(config, &g); err != nil {
|
// NAMESPACES
|
||||||
|
|
||||||
|
if err := config.Pid.ConfigureGenerator(&g); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := addUserNS(config, &g); err != nil {
|
if err := config.User.ConfigureGenerator(&g); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := addNetNS(config, &g); err != nil {
|
if err := config.Network.ConfigureGenerator(&g); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := addUTSNS(config, &g); err != nil {
|
if err := config.Uts.ConfigureGenerator(&g, &config.Network, runtime); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := addIpcNS(config, &g); err != nil {
|
if err := config.Ipc.ConfigureGenerator(&g); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := addCgroupNS(config, &g); err != nil {
|
if err := config.Cgroup.ConfigureGenerator(&g); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
configSpec := g.Config
|
configSpec := g.Config
|
||||||
|
|
||||||
// HANDLE CAPABILITIES
|
if err := config.Security.ConfigureGenerator(&g, &config.User); err != nil {
|
||||||
// NOTE: Must happen before SECCOMP
|
return nil, err
|
||||||
if !config.Privileged {
|
|
||||||
if err := setupCapabilities(config, configSpec); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
g.SetupPrivileged(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
// HANDLE SECCOMP
|
|
||||||
|
|
||||||
if config.SeccompProfilePath != "unconfined" {
|
|
||||||
seccompConfig, err := getSeccompConfig(config, configSpec)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
configSpec.Linux.Seccomp = seccompConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear default Seccomp profile from Generator for privileged containers
|
|
||||||
if config.SeccompProfilePath == "unconfined" || config.Privileged {
|
|
||||||
configSpec.Linux.Seccomp = nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// BIND MOUNTS
|
// BIND MOUNTS
|
||||||
@ -430,7 +352,7 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch config.Cgroups {
|
switch config.Cgroup.Cgroups {
|
||||||
case "disabled":
|
case "disabled":
|
||||||
if addedResources {
|
if addedResources {
|
||||||
return nil, errors.New("cannot specify resource limits when cgroups are disabled is specified")
|
return nil, errors.New("cannot specify resource limits when cgroups are disabled is specified")
|
||||||
@ -461,48 +383,23 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM
|
|||||||
configSpec.Annotations[libpod.InspectAnnotationVolumesFrom] = strings.Join(config.VolumesFrom, ",")
|
configSpec.Annotations[libpod.InspectAnnotationVolumesFrom] = strings.Join(config.VolumesFrom, ",")
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.Privileged {
|
if config.Security.Privileged {
|
||||||
configSpec.Annotations[libpod.InspectAnnotationPrivileged] = libpod.InspectResponseTrue
|
configSpec.Annotations[libpod.InspectAnnotationPrivileged] = libpod.InspectResponseTrue
|
||||||
} else {
|
} else {
|
||||||
configSpec.Annotations[libpod.InspectAnnotationPrivileged] = libpod.InspectResponseFalse
|
configSpec.Annotations[libpod.InspectAnnotationPrivileged] = libpod.InspectResponseFalse
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.PublishAll {
|
|
||||||
configSpec.Annotations[libpod.InspectAnnotationPublishAll] = libpod.InspectResponseTrue
|
|
||||||
} else {
|
|
||||||
configSpec.Annotations[libpod.InspectAnnotationPublishAll] = libpod.InspectResponseFalse
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.Init {
|
if config.Init {
|
||||||
configSpec.Annotations[libpod.InspectAnnotationInit] = libpod.InspectResponseTrue
|
configSpec.Annotations[libpod.InspectAnnotationInit] = libpod.InspectResponseTrue
|
||||||
} else {
|
} else {
|
||||||
configSpec.Annotations[libpod.InspectAnnotationInit] = libpod.InspectResponseFalse
|
configSpec.Annotations[libpod.InspectAnnotationInit] = libpod.InspectResponseFalse
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, opt := range config.SecurityOpts {
|
|
||||||
// Split on both : and =
|
|
||||||
splitOpt := strings.Split(opt, "=")
|
|
||||||
if len(splitOpt) == 1 {
|
|
||||||
splitOpt = strings.Split(opt, ":")
|
|
||||||
}
|
|
||||||
if len(splitOpt) < 2 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
switch splitOpt[0] {
|
|
||||||
case "label":
|
|
||||||
configSpec.Annotations[libpod.InspectAnnotationLabel] = splitOpt[1]
|
|
||||||
case "seccomp":
|
|
||||||
configSpec.Annotations[libpod.InspectAnnotationSeccomp] = splitOpt[1]
|
|
||||||
case "apparmor":
|
|
||||||
configSpec.Annotations[libpod.InspectAnnotationApparmor] = splitOpt[1]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return configSpec, nil
|
return configSpec, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func blockAccessToKernelFilesystems(config *CreateConfig, g *generate.Generator) {
|
func blockAccessToKernelFilesystems(config *CreateConfig, g *generate.Generator) {
|
||||||
if !config.Privileged {
|
if !config.Security.Privileged {
|
||||||
for _, mp := range []string{
|
for _, mp := range []string{
|
||||||
"/proc/acpi",
|
"/proc/acpi",
|
||||||
"/proc/kcore",
|
"/proc/kcore",
|
||||||
@ -518,7 +415,7 @@ func blockAccessToKernelFilesystems(config *CreateConfig, g *generate.Generator)
|
|||||||
g.AddLinuxMaskedPaths(mp)
|
g.AddLinuxMaskedPaths(mp)
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.PidMode.IsHost() && rootless.IsRootless() {
|
if config.Pid.PidMode.IsHost() && rootless.IsRootless() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -535,130 +432,6 @@ func blockAccessToKernelFilesystems(config *CreateConfig, g *generate.Generator)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func addPidNS(config *CreateConfig, g *generate.Generator) error {
|
|
||||||
pidMode := config.PidMode
|
|
||||||
if IsNS(string(pidMode)) {
|
|
||||||
return g.AddOrReplaceLinuxNamespace(string(spec.PIDNamespace), NS(string(pidMode)))
|
|
||||||
}
|
|
||||||
if pidMode.IsHost() {
|
|
||||||
return g.RemoveLinuxNamespace(string(spec.PIDNamespace))
|
|
||||||
}
|
|
||||||
if pidCtr := pidMode.Container(); pidCtr != "" {
|
|
||||||
logrus.Debugf("using container %s pidmode", pidCtr)
|
|
||||||
}
|
|
||||||
if IsPod(string(pidMode)) {
|
|
||||||
logrus.Debug("using pod pidmode")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func addUserNS(config *CreateConfig, g *generate.Generator) error {
|
|
||||||
if IsNS(string(config.UsernsMode)) {
|
|
||||||
if err := g.AddOrReplaceLinuxNamespace(string(spec.UserNamespace), NS(string(config.UsernsMode))); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// runc complains if no mapping is specified, even if we join another ns. So provide a dummy mapping
|
|
||||||
g.AddLinuxUIDMapping(uint32(0), uint32(0), uint32(1))
|
|
||||||
g.AddLinuxGIDMapping(uint32(0), uint32(0), uint32(1))
|
|
||||||
}
|
|
||||||
|
|
||||||
if (len(config.IDMappings.UIDMap) > 0 || len(config.IDMappings.GIDMap) > 0) && !config.UsernsMode.IsHost() {
|
|
||||||
if err := g.AddOrReplaceLinuxNamespace(string(spec.UserNamespace), ""); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func addNetNS(config *CreateConfig, g *generate.Generator) error {
|
|
||||||
netMode := config.NetMode
|
|
||||||
if netMode.IsHost() {
|
|
||||||
logrus.Debug("Using host netmode")
|
|
||||||
return g.RemoveLinuxNamespace(string(spec.NetworkNamespace))
|
|
||||||
} else if netMode.IsNone() {
|
|
||||||
logrus.Debug("Using none netmode")
|
|
||||||
return nil
|
|
||||||
} else if netMode.IsBridge() {
|
|
||||||
logrus.Debug("Using bridge netmode")
|
|
||||||
return nil
|
|
||||||
} else if netCtr := netMode.Container(); netCtr != "" {
|
|
||||||
logrus.Debugf("using container %s netmode", netCtr)
|
|
||||||
return nil
|
|
||||||
} else if IsNS(string(netMode)) {
|
|
||||||
logrus.Debug("Using ns netmode")
|
|
||||||
return g.AddOrReplaceLinuxNamespace(string(spec.NetworkNamespace), NS(string(netMode)))
|
|
||||||
} else if IsPod(string(netMode)) {
|
|
||||||
logrus.Debug("Using pod netmode, unless pod is not sharing")
|
|
||||||
return nil
|
|
||||||
} else if netMode.IsSlirp4netns() {
|
|
||||||
logrus.Debug("Using slirp4netns netmode")
|
|
||||||
return nil
|
|
||||||
} else if netMode.IsUserDefined() {
|
|
||||||
logrus.Debug("Using user defined netmode")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return errors.Errorf("unknown network mode")
|
|
||||||
}
|
|
||||||
|
|
||||||
func addUTSNS(config *CreateConfig, g *generate.Generator) error {
|
|
||||||
utsMode := config.UtsMode
|
|
||||||
if IsNS(string(utsMode)) {
|
|
||||||
return g.AddOrReplaceLinuxNamespace(string(spec.UTSNamespace), NS(string(utsMode)))
|
|
||||||
}
|
|
||||||
if utsMode.IsHost() {
|
|
||||||
return g.RemoveLinuxNamespace(string(spec.UTSNamespace))
|
|
||||||
}
|
|
||||||
if utsCtr := utsMode.Container(); utsCtr != "" {
|
|
||||||
logrus.Debugf("using container %s utsmode", utsCtr)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func addIpcNS(config *CreateConfig, g *generate.Generator) error {
|
|
||||||
ipcMode := config.IpcMode
|
|
||||||
if IsNS(string(ipcMode)) {
|
|
||||||
return g.AddOrReplaceLinuxNamespace(string(spec.IPCNamespace), NS(string(ipcMode)))
|
|
||||||
}
|
|
||||||
if ipcMode.IsHost() {
|
|
||||||
return g.RemoveLinuxNamespace(string(spec.IPCNamespace))
|
|
||||||
}
|
|
||||||
if ipcCtr := ipcMode.Container(); ipcCtr != "" {
|
|
||||||
logrus.Debugf("Using container %s ipcmode", ipcCtr)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func addCgroupNS(config *CreateConfig, g *generate.Generator) error {
|
|
||||||
cgroupMode := config.CgroupMode
|
|
||||||
|
|
||||||
if cgroupMode.IsDefaultValue() {
|
|
||||||
// If the value is not specified, default to "private" on cgroups v2 and "host" on cgroups v1.
|
|
||||||
unified, err := cgroups.IsCgroup2UnifiedMode()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if unified {
|
|
||||||
cgroupMode = "private"
|
|
||||||
} else {
|
|
||||||
cgroupMode = "host"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if cgroupMode.IsNS() {
|
|
||||||
return g.AddOrReplaceLinuxNamespace(string(spec.CgroupNamespace), NS(string(cgroupMode)))
|
|
||||||
}
|
|
||||||
if cgroupMode.IsHost() {
|
|
||||||
return g.RemoveLinuxNamespace(string(spec.CgroupNamespace))
|
|
||||||
}
|
|
||||||
if cgroupMode.IsPrivate() {
|
|
||||||
return g.AddOrReplaceLinuxNamespace(string(spec.CgroupNamespace), "")
|
|
||||||
}
|
|
||||||
if cgCtr := cgroupMode.Container(); cgCtr != "" {
|
|
||||||
logrus.Debugf("Using container %s cgroup mode", cgCtr)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func addRlimits(config *CreateConfig, g *generate.Generator) error {
|
func addRlimits(config *CreateConfig, g *generate.Generator) error {
|
||||||
var (
|
var (
|
||||||
kernelMax uint64 = 1048576
|
kernelMax uint64 = 1048576
|
||||||
@ -702,37 +475,3 @@ func addRlimits(config *CreateConfig, g *generate.Generator) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupCapabilities(config *CreateConfig, configSpec *spec.Spec) error {
|
|
||||||
useNotRoot := func(user string) bool {
|
|
||||||
if user == "" || user == "root" || user == "0" {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
var err error
|
|
||||||
var caplist []string
|
|
||||||
bounding := configSpec.Process.Capabilities.Bounding
|
|
||||||
if useNotRoot(config.User) {
|
|
||||||
configSpec.Process.Capabilities.Bounding = caplist
|
|
||||||
}
|
|
||||||
caplist, err = caps.TweakCapabilities(configSpec.Process.Capabilities.Bounding, config.CapAdd, config.CapDrop, nil, false)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
configSpec.Process.Capabilities.Bounding = caplist
|
|
||||||
configSpec.Process.Capabilities.Permitted = caplist
|
|
||||||
configSpec.Process.Capabilities.Inheritable = caplist
|
|
||||||
configSpec.Process.Capabilities.Effective = caplist
|
|
||||||
configSpec.Process.Capabilities.Ambient = caplist
|
|
||||||
if useNotRoot(config.User) {
|
|
||||||
caplist, err = caps.TweakCapabilities(bounding, config.CapAdd, config.CapDrop, nil, false)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
configSpec.Process.Capabilities.Bounding = caplist
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
@ -21,9 +21,9 @@ var (
|
|||||||
func makeTestCreateConfig() *CreateConfig {
|
func makeTestCreateConfig() *CreateConfig {
|
||||||
cc := new(CreateConfig)
|
cc := new(CreateConfig)
|
||||||
cc.Resources = CreateResourceConfig{}
|
cc.Resources = CreateResourceConfig{}
|
||||||
cc.IDMappings = new(storage.IDMappingOptions)
|
cc.User.IDMappings = new(storage.IDMappingOptions)
|
||||||
cc.IDMappings.UIDMap = []idtools.IDMap{}
|
cc.User.IDMappings.UIDMap = []idtools.IDMap{}
|
||||||
cc.IDMappings.GIDMap = []idtools.IDMap{}
|
cc.User.IDMappings.GIDMap = []idtools.IDMap{}
|
||||||
|
|
||||||
return cc
|
return cc
|
||||||
}
|
}
|
||||||
|
@ -160,7 +160,7 @@ func (config *CreateConfig) parseVolumes(runtime *libpod.Runtime) ([]spec.Mount,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If requested, add tmpfs filesystems for read-only containers.
|
// If requested, add tmpfs filesystems for read-only containers.
|
||||||
if config.ReadOnlyRootfs && config.ReadOnlyTmpfs {
|
if config.Security.ReadOnlyRootfs && config.Security.ReadOnlyTmpfs {
|
||||||
readonlyTmpfs := []string{"/tmp", "/var/tmp", "/run"}
|
readonlyTmpfs := []string{"/tmp", "/var/tmp", "/run"}
|
||||||
options := []string{"rw", "rprivate", "nosuid", "nodev", "tmpcopyup"}
|
options := []string{"rw", "rprivate", "nosuid", "nodev", "tmpcopyup"}
|
||||||
for _, dest := range readonlyTmpfs {
|
for _, dest := range readonlyTmpfs {
|
||||||
@ -807,7 +807,7 @@ func (config *CreateConfig) addContainerInitBinary(path string) (spec.Mount, err
|
|||||||
if path == "" {
|
if path == "" {
|
||||||
return mount, fmt.Errorf("please specify a path to the container-init binary")
|
return mount, fmt.Errorf("please specify a path to the container-init binary")
|
||||||
}
|
}
|
||||||
if !config.PidMode.IsPrivate() {
|
if !config.Pid.PidMode.IsPrivate() {
|
||||||
return mount, fmt.Errorf("cannot add init binary as PID 1 (PID namespace isn't private)")
|
return mount, fmt.Errorf("cannot add init binary as PID 1 (PID namespace isn't private)")
|
||||||
}
|
}
|
||||||
if config.Systemd {
|
if config.Systemd {
|
||||||
|
2
vendor/modules.txt
vendored
2
vendor/modules.txt
vendored
@ -382,8 +382,8 @@ github.com/opencontainers/runtime-tools/filepath
|
|||||||
github.com/opencontainers/runtime-tools/specerror
|
github.com/opencontainers/runtime-tools/specerror
|
||||||
github.com/opencontainers/runtime-tools/error
|
github.com/opencontainers/runtime-tools/error
|
||||||
# github.com/opencontainers/selinux v1.3.0
|
# github.com/opencontainers/selinux v1.3.0
|
||||||
github.com/opencontainers/selinux/go-selinux/label
|
|
||||||
github.com/opencontainers/selinux/go-selinux
|
github.com/opencontainers/selinux/go-selinux
|
||||||
|
github.com/opencontainers/selinux/go-selinux/label
|
||||||
# github.com/openshift/api v3.9.1-0.20190810003144-27fb16909b15+incompatible
|
# github.com/openshift/api v3.9.1-0.20190810003144-27fb16909b15+incompatible
|
||||||
github.com/openshift/api/config/v1
|
github.com/openshift/api/config/v1
|
||||||
# github.com/openshift/imagebuilder v1.1.1
|
# github.com/openshift/imagebuilder v1.1.1
|
||||||
|
Reference in New Issue
Block a user