Add support for process overrides of settings
This commit adds support to libcontainer to allow caps, no new privs, apparmor, and selinux process label to the process struct so that it can be used together of override the base settings on the container config per individual process. Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
This commit is contained in:
parent
aa9660027b
commit
3cc90bd2d8
31
exec.go
31
exec.go
|
@ -48,7 +48,7 @@ following will output a list of processes running in the container:
|
|||
Usage: "UID (format: <uid>[:<gid>])",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "process,p",
|
||||
Name: "process, p",
|
||||
Usage: "path to the process.json",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
|
@ -60,6 +60,23 @@ following will output a list of processes running in the container:
|
|||
Value: "",
|
||||
Usage: "specify the file to write the process id to",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "process-label",
|
||||
Usage: "set the asm process label for the process commonly used with selinux",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "apparmor",
|
||||
Usage: "set the apparmor profile for the process",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "no-new-privs",
|
||||
Usage: "set the no new privileges value for the process",
|
||||
},
|
||||
cli.StringSliceFlag{
|
||||
Name: "cap, c",
|
||||
Value: &cli.StringSlice{},
|
||||
Usage: "add a capability to the bounding set for the process",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) {
|
||||
if os.Geteuid() != 0 {
|
||||
|
@ -118,6 +135,15 @@ func getProcess(context *cli.Context, bundle string) (*specs.Process, error) {
|
|||
if context.String("cwd") != "" {
|
||||
p.Cwd = context.String("cwd")
|
||||
}
|
||||
if ap := context.String("apparmor"); ap != "" {
|
||||
p.ApparmorProfile = ap
|
||||
}
|
||||
if l := context.String("process-label"); l != "" {
|
||||
p.SelinuxLabel = l
|
||||
}
|
||||
if caps := context.StringSlice("cap"); len(caps) > 0 {
|
||||
p.Capabilities = caps
|
||||
}
|
||||
// append the passed env variables
|
||||
for _, e := range context.StringSlice("env") {
|
||||
p.Env = append(p.Env, e)
|
||||
|
@ -126,6 +152,9 @@ func getProcess(context *cli.Context, bundle string) (*specs.Process, error) {
|
|||
if context.IsSet("tty") {
|
||||
p.Terminal = context.Bool("tty")
|
||||
}
|
||||
if context.IsSet("no-new-privs") {
|
||||
p.NoNewPrivileges = context.Bool("no-new-privs")
|
||||
}
|
||||
// override the user, if passed
|
||||
if context.String("user") != "" {
|
||||
u := strings.SplitN(context.String("user"), ":", 2)
|
||||
|
|
|
@ -128,11 +128,11 @@ type Config struct {
|
|||
|
||||
// AppArmorProfile specifies the profile to apply to the process running in the container and is
|
||||
// change at the time the process is execed
|
||||
AppArmorProfile string `json:"apparmor_profile"`
|
||||
AppArmorProfile string `json:"apparmor_profile,omitempty"`
|
||||
|
||||
// ProcessLabel specifies the label to apply to the process running in the container. It is
|
||||
// commonly used by selinux
|
||||
ProcessLabel string `json:"process_label"`
|
||||
ProcessLabel string `json:"process_label,omitempty"`
|
||||
|
||||
// Rlimits specifies the resource limits, such as max open files, to set in the container
|
||||
// If Rlimits are not set, the container will inherit rlimits from the parent process
|
||||
|
@ -172,7 +172,7 @@ type Config struct {
|
|||
Seccomp *Seccomp `json:"seccomp"`
|
||||
|
||||
// NoNewPrivileges controls whether processes in the container can gain additional privileges.
|
||||
NoNewPrivileges bool `json:"no_new_privileges"`
|
||||
NoNewPrivileges bool `json:"no_new_privileges,omitempty"`
|
||||
|
||||
// Hooks are a collection of actions to perform at various container lifecycle events.
|
||||
// Hooks are not able to be marshaled to json but they are also not needed to.
|
||||
|
|
|
@ -319,7 +319,7 @@ func (c *linuxContainer) newSetnsProcess(p *Process, cmd *exec.Cmd, parentPipe,
|
|||
}
|
||||
|
||||
func (c *linuxContainer) newInitConfig(process *Process) *initConfig {
|
||||
return &initConfig{
|
||||
cfg := &initConfig{
|
||||
Config: c.config,
|
||||
Args: process.Args,
|
||||
Env: process.Env,
|
||||
|
@ -329,7 +329,20 @@ func (c *linuxContainer) newInitConfig(process *Process) *initConfig {
|
|||
Capabilities: process.Capabilities,
|
||||
PassedFilesCount: len(process.ExtraFiles),
|
||||
ContainerId: c.ID(),
|
||||
NoNewPrivileges: c.config.NoNewPrivileges,
|
||||
AppArmorProfile: c.config.AppArmorProfile,
|
||||
ProcessLabel: c.config.ProcessLabel,
|
||||
}
|
||||
if process.NoNewPrivileges != nil {
|
||||
cfg.NoNewPrivileges = *process.NoNewPrivileges
|
||||
}
|
||||
if process.AppArmorProfile != "" {
|
||||
cfg.AppArmorProfile = process.AppArmorProfile
|
||||
}
|
||||
if process.Label != "" {
|
||||
cfg.ProcessLabel = process.Label
|
||||
}
|
||||
return cfg
|
||||
}
|
||||
|
||||
func newPipe() (parent *os.File, child *os.File, err error) {
|
||||
|
|
|
@ -48,6 +48,9 @@ type initConfig struct {
|
|||
Env []string `json:"env"`
|
||||
Cwd string `json:"cwd"`
|
||||
Capabilities []string `json:"capabilities"`
|
||||
ProcessLabel string `json:"process_label"`
|
||||
AppArmorProfile string `json:"apparmor_profile"`
|
||||
NoNewPrivileges bool `json:"no_new_privileges"`
|
||||
User string `json:"user"`
|
||||
Config *configs.Config `json:"config"`
|
||||
Console string `json:"console"`
|
||||
|
|
|
@ -48,6 +48,16 @@ type Process struct {
|
|||
// All capabilities not specified will be dropped from the processes capability mask
|
||||
Capabilities []string
|
||||
|
||||
// AppArmorProfile specifies the profile to apply to the process and is
|
||||
// changed at the time the process is execed
|
||||
AppArmorProfile string
|
||||
|
||||
// Label specifies the label to apply to the process. It is commonly used by selinux
|
||||
Label string
|
||||
|
||||
// NoNewPrivileges controls whether processes can gain additional privileges.
|
||||
NoNewPrivileges *bool
|
||||
|
||||
ops processOperations
|
||||
}
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ func (l *linuxSetnsInit) Init() error {
|
|||
if err := setOomScoreAdj(l.config.Config.OomScoreAdj); err != nil {
|
||||
return err
|
||||
}
|
||||
if l.config.Config.NoNewPrivileges {
|
||||
if l.config.NoNewPrivileges {
|
||||
if err := system.Prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -47,11 +47,11 @@ func (l *linuxSetnsInit) Init() error {
|
|||
if err := finalizeNamespace(l.config); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := apparmor.ApplyProfile(l.config.Config.AppArmorProfile); err != nil {
|
||||
if err := apparmor.ApplyProfile(l.config.AppArmorProfile); err != nil {
|
||||
return err
|
||||
}
|
||||
if l.config.Config.ProcessLabel != "" {
|
||||
if err := label.SetProcessLabel(l.config.Config.ProcessLabel); err != nil {
|
||||
if l.config.ProcessLabel != "" {
|
||||
if err := label.SetProcessLabel(l.config.ProcessLabel); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
|
@ -91,10 +91,10 @@ func (l *linuxStandardInit) Init() error {
|
|||
return err
|
||||
}
|
||||
}
|
||||
if err := apparmor.ApplyProfile(l.config.Config.AppArmorProfile); err != nil {
|
||||
if err := apparmor.ApplyProfile(l.config.AppArmorProfile); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := label.SetProcessLabel(l.config.Config.ProcessLabel); err != nil {
|
||||
if err := label.SetProcessLabel(l.config.ProcessLabel); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -117,7 +117,7 @@ func (l *linuxStandardInit) Init() error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if l.config.Config.NoNewPrivileges {
|
||||
if l.config.NoNewPrivileges {
|
||||
if err := system.Prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
10
spec.go
10
spec.go
|
@ -245,10 +245,9 @@ func createLibcontainerConfig(cgroupName string, spec *specs.LinuxSpec) (*config
|
|||
rootfsPath = filepath.Join(cwd, rootfsPath)
|
||||
}
|
||||
config := &configs.Config{
|
||||
Rootfs: rootfsPath,
|
||||
Capabilities: spec.Process.Capabilities,
|
||||
Readonlyfs: spec.Root.Readonly,
|
||||
Hostname: spec.Hostname,
|
||||
Rootfs: rootfsPath,
|
||||
Readonlyfs: spec.Root.Readonly,
|
||||
Hostname: spec.Hostname,
|
||||
Labels: []string{
|
||||
"bundle=" + cwd,
|
||||
},
|
||||
|
@ -303,9 +302,6 @@ func createLibcontainerConfig(cgroupName string, spec *specs.LinuxSpec) (*config
|
|||
}
|
||||
config.Seccomp = seccomp
|
||||
config.Sysctl = spec.Linux.Sysctl
|
||||
config.ProcessLabel = spec.Process.SelinuxLabel
|
||||
config.AppArmorProfile = spec.Process.ApparmorProfile
|
||||
config.NoNewPrivileges = spec.Process.NoNewPrivileges
|
||||
if oomScoreAdj := spec.Linux.Resources.OOMScoreAdj; oomScoreAdj != nil {
|
||||
config.OomScoreAdj = *oomScoreAdj
|
||||
}
|
||||
|
|
8
utils.go
8
utils.go
|
@ -219,8 +219,12 @@ func newProcess(p specs.Process) *libcontainer.Process {
|
|||
Args: p.Args,
|
||||
Env: p.Env,
|
||||
// TODO: fix libcontainer's API to better support uid/gid in a typesafe way.
|
||||
User: fmt.Sprintf("%d:%d", p.User.UID, p.User.GID),
|
||||
Cwd: p.Cwd,
|
||||
User: fmt.Sprintf("%d:%d", p.User.UID, p.User.GID),
|
||||
Cwd: p.Cwd,
|
||||
Capabilities: p.Capabilities,
|
||||
Label: p.SelinuxLabel,
|
||||
NoNewPrivileges: &p.NoNewPrivileges,
|
||||
AppArmorProfile: p.ApparmorProfile,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue