diff options
Diffstat (limited to 'pkg/spec/spec.go')
-rw-r--r-- | pkg/spec/spec.go | 315 |
1 files changed, 27 insertions, 288 deletions
diff --git a/pkg/spec/spec.go b/pkg/spec/spec.go index 33e9ec076..7a220012f 100644 --- a/pkg/spec/spec.go +++ b/pkg/spec/spec.go @@ -1,7 +1,6 @@ package createconfig import ( - "os" "strings" "github.com/containers/libpod/libpod" @@ -10,13 +9,11 @@ import ( "github.com/containers/libpod/pkg/cgroups" "github.com/containers/libpod/pkg/rootless" "github.com/containers/libpod/pkg/sysinfo" - "github.com/docker/docker/oci/caps" "github.com/docker/go-units" "github.com/opencontainers/runc/libcontainer/user" spec "github.com/opencontainers/runtime-spec/specs-go" "github.com/opencontainers/runtime-tools/generate" "github.com/pkg/errors" - "github.com/sirupsen/logrus" ) const cpuPeriod = 100000 @@ -47,14 +44,13 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM canMountSys := true isRootless := rootless.IsRootless() - hasUserns := config.UsernsMode.IsContainer() || config.UsernsMode.IsNS() || len(config.IDMappings.UIDMap) > 0 || len(config.IDMappings.GIDMap) > 0 - inUserNS := isRootless || (hasUserns && !config.UsernsMode.IsHost()) + inUserNS := config.User.InNS(isRootless) - if inUserNS && config.NetMode.IsHost() { + if inUserNS && config.Network.NetMode.IsHost() { canMountSys = false } - if config.Privileged && canMountSys { + if config.Security.Privileged && canMountSys { cgroupPerm = "rw" g.RemoveMount("/sys") sysMnt := spec.Mount{ @@ -68,7 +64,7 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM addCgroup = false g.RemoveMount("/sys") r := "ro" - if config.Privileged { + if config.Security.Privileged { r = "rw" } sysMnt := spec.Mount{ @@ -78,7 +74,7 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM Options: []string{"rprivate", "nosuid", "noexec", "nodev", r, "rbind"}, } g.AddMount(sysMnt) - if !config.Privileged && isRootless { + if !config.Security.Privileged && isRootless { 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 // the container. - if gid5Available && len(config.IDMappings.GIDMap) > 0 { + if gid5Available && len(config.User.IDMappings.GIDMap) > 0 { mappingFound := false - for _, r := range config.IDMappings.GIDMap { + for _, r := range config.User.IDMappings.GIDMap { if r.ContainerID <= 5 && 5 < r.ContainerID+r.Size { mappingFound = true break @@ -117,7 +113,7 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM g.AddMount(devPts) } - if inUserNS && config.IpcMode.IsHost() { + if inUserNS && config.Ipc.IpcMode.IsHost() { g.RemoveMount("/dev/mqueue") devMqueue := spec.Mount{ Destination: "/dev/mqueue", @@ -127,7 +123,7 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM } g.AddMount(devMqueue) } - if inUserNS && config.PidMode.IsHost() { + if inUserNS && config.Pid.PidMode.IsHost() { g.RemoveMount("/proc") procMount := spec.Mount{ Destination: "/proc", @@ -154,55 +150,6 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM for key, val := range config.Annotations { 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") addedResources := false @@ -272,7 +219,7 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM } // Devices - if config.Privileged { + if config.Security.Privileged { // If privileged, we need to add all the host devices to the // spec. We do not add the user provided ones because we are // 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 - g.SetProcessNoNewPrivileges(config.NoNewPrivs) + g.SetProcessNoNewPrivileges(config.Security.NoNewPrivs) - if !config.Privileged { - g.SetProcessApparmorProfile(config.ApparmorProfile) + if !config.Security.Privileged { + g.SetProcessApparmorProfile(config.Security.ApparmorProfile) } blockAccessToKernelFilesystems(config, &g) @@ -341,54 +282,35 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM return nil, err } - if err := addPidNS(config, &g); err != nil { + // NAMESPACES + + if err := config.Pid.ConfigureGenerator(&g); err != nil { return nil, err } - if err := addUserNS(config, &g); err != nil { + if err := config.User.ConfigureGenerator(&g); err != nil { return nil, err } - if err := addNetNS(config, &g); err != nil { + if err := config.Network.ConfigureGenerator(&g); err != nil { return nil, err } - if err := addUTSNS(config, &g); err != nil { + if err := config.Uts.ConfigureGenerator(&g, &config.Network, runtime); err != nil { return nil, err } - if err := addIpcNS(config, &g); err != nil { + if err := config.Ipc.ConfigureGenerator(&g); err != nil { return nil, err } - if err := addCgroupNS(config, &g); err != nil { + if err := config.Cgroup.ConfigureGenerator(&g); err != nil { return nil, err } configSpec := g.Config - // HANDLE CAPABILITIES - // NOTE: Must happen before SECCOMP - 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 + if err := config.Security.ConfigureGenerator(&g, &config.User); err != nil { + return nil, err } // BIND MOUNTS @@ -430,7 +352,7 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM } } - switch config.Cgroups { + switch config.Cgroup.Cgroups { case "disabled": if addedResources { 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, ",") } - if config.Privileged { + if config.Security.Privileged { configSpec.Annotations[libpod.InspectAnnotationPrivileged] = libpod.InspectResponseTrue } else { 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 { configSpec.Annotations[libpod.InspectAnnotationInit] = libpod.InspectResponseTrue } else { 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 } func blockAccessToKernelFilesystems(config *CreateConfig, g *generate.Generator) { - if !config.Privileged { + if !config.Security.Privileged { for _, mp := range []string{ "/proc/acpi", "/proc/kcore", @@ -518,7 +415,7 @@ func blockAccessToKernelFilesystems(config *CreateConfig, g *generate.Generator) g.AddLinuxMaskedPaths(mp) } - if config.PidMode.IsHost() && rootless.IsRootless() { + if config.Pid.PidMode.IsHost() && rootless.IsRootless() { 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 { var ( kernelMax uint64 = 1048576 @@ -702,37 +475,3 @@ func addRlimits(config *CreateConfig, g *generate.Generator) error { 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 -} |