diff options
Diffstat (limited to 'pkg')
-rw-r--r-- | pkg/domain/entities/types.go | 1 | ||||
-rw-r--r-- | pkg/specgen/generate/container.go | 83 | ||||
-rw-r--r-- | pkg/specgen/generate/namespaces.go | 62 | ||||
-rw-r--r-- | pkg/specgen/generate/security.go | 110 |
4 files changed, 107 insertions, 149 deletions
diff --git a/pkg/domain/entities/types.go b/pkg/domain/entities/types.go index b89aa869a..096af2df2 100644 --- a/pkg/domain/entities/types.go +++ b/pkg/domain/entities/types.go @@ -50,6 +50,7 @@ type InspectOptions struct { Format string `json:",omitempty"` Latest bool `json:",omitempty"` Size bool `json:",omitempty"` + Type string `json:",omitempty"` } // All API and CLI diff commands and diff sub-commands use the same options diff --git a/pkg/specgen/generate/container.go b/pkg/specgen/generate/container.go index 7233acb8a..31465d8bf 100644 --- a/pkg/specgen/generate/container.go +++ b/pkg/specgen/generate/container.go @@ -20,17 +20,27 @@ func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerat } // Image stop signal - if s.StopSignal == nil && newImage.Config != nil { - sig, err := signal.ParseSignalNameOrNumber(newImage.Config.StopSignal) + if s.StopSignal == nil { + stopSignal, err := newImage.StopSignal(ctx) + if err != nil { + return err + } + sig, err := signal.ParseSignalNameOrNumber(stopSignal) if err != nil { return err } s.StopSignal = &sig } + // Image envs from the image if they don't exist // already - if newImage.Config != nil && len(newImage.Config.Env) > 0 { - envs, err := envLib.ParseSlice(newImage.Config.Env) + env, err := newImage.Env(ctx) + if err != nil { + return err + } + + if len(env) > 0 { + envs, err := envLib.ParseSlice(env) if err != nil { return err } @@ -41,12 +51,15 @@ func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerat } } + labels, err := newImage.Labels(ctx) + if err != nil { + return err + } + // labels from the image that dont exist already - if config := newImage.Config; config != nil { - for k, v := range config.Labels { - if _, exists := s.Labels[k]; !exists { - s.Labels[k] = v - } + for k, v := range labels { + if _, exists := s.Labels[k]; !exists { + s.Labels[k] = v } } @@ -75,20 +88,30 @@ func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerat } // entrypoint - if config := newImage.Config; config != nil { - if len(s.Entrypoint) < 1 && len(config.Entrypoint) > 0 { - s.Entrypoint = config.Entrypoint - } - if len(s.Command) < 1 && len(config.Cmd) > 0 { - s.Command = config.Cmd - } - if len(s.Command) < 1 && len(s.Entrypoint) < 1 { - return errors.Errorf("No command provided or as CMD or ENTRYPOINT in this image") - } - // workdir - if len(s.WorkDir) < 1 && len(config.WorkingDir) > 1 { - s.WorkDir = config.WorkingDir - } + entrypoint, err := newImage.Entrypoint(ctx) + if err != nil { + return err + } + if len(s.Entrypoint) < 1 && len(entrypoint) > 0 { + s.Entrypoint = entrypoint + } + command, err := newImage.Cmd(ctx) + if err != nil { + return err + } + if len(s.Command) < 1 && len(command) > 0 { + s.Command = command + } + if len(s.Command) < 1 && len(s.Entrypoint) < 1 { + return errors.Errorf("No command provided or as CMD or ENTRYPOINT in this image") + } + // workdir + workingDir, err := newImage.WorkingDir(ctx) + if err != nil { + return err + } + if len(s.WorkDir) < 1 && len(workingDir) > 1 { + s.WorkDir = workingDir } if len(s.SeccompProfilePath) < 1 { @@ -99,15 +122,17 @@ func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerat s.SeccompProfilePath = p } - if user := s.User; len(user) == 0 { - switch { + if len(s.User) == 0 { + s.User, err = newImage.User(ctx) + if err != nil { + return err + } + // TODO This should be enabled when namespaces actually work //case usernsMode.IsKeepID(): // user = fmt.Sprintf("%d:%d", rootless.GetRootlessUID(), rootless.GetRootlessGID()) - case newImage.Config == nil || (newImage.Config != nil && len(newImage.Config.User) == 0): + if len(s.User) == 0 { s.User = "0" - default: - s.User = newImage.Config.User } } if err := finishThrottleDevices(s); err != nil { @@ -116,7 +141,7 @@ func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerat // Unless already set via the CLI, check if we need to disable process // labels or set the defaults. if len(s.SelinuxOpts) == 0 { - if err := SetLabelOpts(s, r, s.PidNS, s.IpcNS); err != nil { + if err := setLabelOpts(s, r, s.PidNS, s.IpcNS); err != nil { return err } } diff --git a/pkg/specgen/generate/namespaces.go b/pkg/specgen/generate/namespaces.go index cdd7d86da..53ae335c3 100644 --- a/pkg/specgen/generate/namespaces.go +++ b/pkg/specgen/generate/namespaces.go @@ -3,9 +3,7 @@ package generate import ( "os" - "github.com/containers/common/pkg/capabilities" "github.com/containers/libpod/libpod" - "github.com/containers/libpod/libpod/image" "github.com/containers/libpod/pkg/specgen" "github.com/cri-o/ocicni/pkg/ocicni" spec "github.com/opencontainers/runtime-spec/specs-go" @@ -324,66 +322,6 @@ func userConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator) err return nil } -func securityConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator, newImage *image.Image) error { - // HANDLE CAPABILITIES - // NOTE: Must happen before SECCOMP - if s.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(s.User) { - configSpec.Process.Capabilities.Bounding = caplist - } - caplist, err = capabilities.MergeCapabilities(configSpec.Process.Capabilities.Bounding, s.CapAdd, s.CapDrop) - 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(s.User) { - caplist, err = capabilities.MergeCapabilities(bounding, s.CapAdd, s.CapDrop) - if err != nil { - return err - } - } - configSpec.Process.Capabilities.Bounding = caplist - - // HANDLE SECCOMP - if s.SeccompProfilePath != "unconfined" { - seccompConfig, err := getSeccompConfig(s, configSpec, newImage) - if err != nil { - return err - } - configSpec.Linux.Seccomp = seccompConfig - } - - // Clear default Seccomp profile from Generator for privileged containers - if s.SeccompProfilePath == "unconfined" || s.Privileged { - configSpec.Linux.Seccomp = nil - } - - g.SetRootReadonly(s.ReadOnlyFilesystem) - for sysctlKey, sysctlVal := range s.Sysctl { - g.AddLinuxSysctl(sysctlKey, sysctlVal) - } - - return nil -} - // GetNamespaceOptions transforms a slice of kernel namespaces // into a slice of pod create options. Currently, not all // kernel namespaces are supported, and they will be returned in an error diff --git a/pkg/specgen/generate/security.go b/pkg/specgen/generate/security.go index ef4b3b47a..e2da9e976 100644 --- a/pkg/specgen/generate/security.go +++ b/pkg/specgen/generate/security.go @@ -1,15 +1,22 @@ package generate import ( + "strings" + + "github.com/containers/common/pkg/capabilities" "github.com/containers/libpod/libpod" + "github.com/containers/libpod/libpod/image" "github.com/containers/libpod/pkg/specgen" + "github.com/containers/libpod/pkg/util" + "github.com/opencontainers/runtime-tools/generate" "github.com/opencontainers/selinux/go-selinux/label" "github.com/pkg/errors" + "github.com/sirupsen/logrus" ) -// SetLabelOpts sets the label options of the SecurityConfig according to the +// setLabelOpts sets the label options of the SecurityConfig according to the // input. -func SetLabelOpts(s *specgen.SpecGenerator, runtime *libpod.Runtime, pidConfig specgen.Namespace, ipcConfig specgen.Namespace) error { +func setLabelOpts(s *specgen.SpecGenerator, runtime *libpod.Runtime, pidConfig specgen.Namespace, ipcConfig specgen.Namespace) error { if !runtime.EnableLabeling() || s.Privileged { s.SelinuxOpts = label.DisableSecOpt() return nil @@ -48,12 +55,10 @@ func SetLabelOpts(s *specgen.SpecGenerator, runtime *libpod.Runtime, pidConfig s return nil } -// ConfigureGenerator configures the generator according to the input. -/* -func (c *SecurityConfig) ConfigureGenerator(g *generate.Generator, user *UserConfig) error { +func securityConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator, newImage *image.Image) error { // HANDLE CAPABILITIES // NOTE: Must happen before SECCOMP - if c.Privileged { + if s.Privileged { g.SetupPrivileged(true) } @@ -63,56 +68,66 @@ func (c *SecurityConfig) ConfigureGenerator(g *generate.Generator, user *UserCon } return true } - configSpec := g.Config var err error - var defaultCaplist []string + var caplist []string bounding := configSpec.Process.Capabilities.Bounding - if useNotRoot(user.User) { - configSpec.Process.Capabilities.Bounding = defaultCaplist + if useNotRoot(s.User) { + configSpec.Process.Capabilities.Bounding = caplist } - defaultCaplist, err = capabilities.MergeCapabilities(configSpec.Process.Capabilities.Bounding, c.CapAdd, c.CapDrop) + caplist, err = capabilities.MergeCapabilities(configSpec.Process.Capabilities.Bounding, s.CapAdd, s.CapDrop) if err != nil { return err } + privCapsRequired := []string{} + + // If the container image specifies an label with a + // capabilities.ContainerImageLabel then split the comma separated list + // of capabilities and record them. This list indicates the only + // capabilities, required to run the container. + var capsRequiredRequested []string + for key, val := range s.Labels { + if util.StringInSlice(key, capabilities.ContainerImageLabels) { + capsRequiredRequested = strings.Split(val, ",") + } + } + if !s.Privileged && len(capsRequiredRequested) > 0 { - privCapRequired := []string{} - - if !c.Privileged && len(c.CapRequired) > 0 { - // Pass CapRequired in CapAdd field to normalize capabilities names - capRequired, err := capabilities.MergeCapabilities(nil, c.CapRequired, nil) + // Pass capRequiredRequested in CapAdd field to normalize capabilities names + capsRequired, err := capabilities.MergeCapabilities(nil, capsRequiredRequested, nil) if err != nil { - logrus.Errorf("capabilities requested by user or image are not valid: %q", strings.Join(c.CapRequired, ",")) + logrus.Errorf("capabilities requested by user or image are not valid: %q", strings.Join(capsRequired, ",")) } else { - // Verify all capRequiered are in the defaultCapList - for _, cap := range capRequired { - if !util.StringInSlice(cap, defaultCaplist) { - privCapRequired = append(privCapRequired, cap) + // Verify all capRequiered are in the capList + for _, cap := range capsRequired { + if !util.StringInSlice(cap, caplist) { + privCapsRequired = append(privCapsRequired, cap) } } } - if len(privCapRequired) == 0 { - defaultCaplist = capRequired + if len(privCapsRequired) == 0 { + caplist = capsRequired } else { - logrus.Errorf("capabilities requested by user or image are not allowed by default: %q", strings.Join(privCapRequired, ",")) + logrus.Errorf("capabilities requested by user or image are not allowed by default: %q", strings.Join(privCapsRequired, ",")) } } - configSpec.Process.Capabilities.Bounding = defaultCaplist - configSpec.Process.Capabilities.Permitted = defaultCaplist - configSpec.Process.Capabilities.Inheritable = defaultCaplist - configSpec.Process.Capabilities.Effective = defaultCaplist - configSpec.Process.Capabilities.Ambient = defaultCaplist - if useNotRoot(user.User) { - defaultCaplist, err = capabilities.MergeCapabilities(bounding, c.CapAdd, c.CapDrop) + + 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(s.User) { + caplist, err = capabilities.MergeCapabilities(bounding, s.CapAdd, s.CapDrop) if err != nil { return err } } - configSpec.Process.Capabilities.Bounding = defaultCaplist + configSpec.Process.Capabilities.Bounding = caplist // HANDLE SECCOMP - if c.SeccompProfilePath != "unconfined" { - seccompConfig, err := getSeccompConfig(c, configSpec) + if s.SeccompProfilePath != "unconfined" { + seccompConfig, err := getSeccompConfig(s, configSpec, newImage) if err != nil { return err } @@ -120,35 +135,14 @@ func (c *SecurityConfig) ConfigureGenerator(g *generate.Generator, user *UserCon } // Clear default Seccomp profile from Generator for privileged containers - if c.SeccompProfilePath == "unconfined" || c.Privileged { + if s.SeccompProfilePath == "unconfined" || s.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.SetRootReadonly(s.ReadOnlyFilesystem) + for sysctlKey, sysctlVal := range s.Sysctl { g.AddLinuxSysctl(sysctlKey, sysctlVal) } return nil } - -*/ |