summaryrefslogtreecommitdiff
path: root/pkg/spec/spec.go
diff options
context:
space:
mode:
authorPeter Hunt <pehunt@redhat.com>2019-09-11 16:50:02 -0400
committerPeter Hunt <pehunt@redhat.com>2019-11-07 21:23:23 -0500
commitdcf3c742b1ac4d641d66810113f3d17441a412f4 (patch)
tree2112a19ba95287179b0a44bbd90719a86d317c5d /pkg/spec/spec.go
parent3463a7194c504790e73a1750109c1813a7c3cfe9 (diff)
downloadpodman-dcf3c742b1ac4d641d66810113f3d17441a412f4.tar.gz
podman-dcf3c742b1ac4d641d66810113f3d17441a412f4.tar.bz2
podman-dcf3c742b1ac4d641d66810113f3d17441a412f4.zip
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>
Diffstat (limited to 'pkg/spec/spec.go')
-rw-r--r--pkg/spec/spec.go315
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
-}