func (aci *Aci) prepareBuildAci() (string, error) { logs.WithFields(aci.fields).Debug("Preparing builder") if err := os.MkdirAll(aci.target+pathBuilder+common.PathRootfs, 0777); err != nil { return "", errs.WithEF(err, aci.fields.WithField("path", aci.target+pathBuilder), "Failed to create builder aci path") } if err := ioutil.WriteFile(aci.target+pathBuilder+common.PathRootfs+"/.keep", []byte(""), 0644); err != nil { return "", errs.WithEF(err, aci.fields.WithField("file", aci.target+pathBuilder+common.PathRootfs+"/.keep"), "Failed to write keep file") } capa, err := types.NewLinuxCapabilitiesRetainSet("all") if err != nil { return "", errs.WithEF(err, aci.fields, "Failed to create all capability retain Set") } allIsolator, err := capa.AsIsolator() if err != nil { return "", errs.WithEF(err, aci.fields, "Failed to prepare all retain set isolator") } aci.manifest.Aci.App.Isolators = types.Isolators([]types.Isolator{*allIsolator}) if err := common.WriteAciManifest(aci.manifest, aci.target+pathBuilder+common.PathManifest, common.PrefixBuilder+aci.manifest.NameAndVersion.Name(), BuildVersion); err != nil { return "", err } if err := aci.tarAci(aci.target + pathBuilder); err != nil { return "", err } logs.WithF(aci.fields.WithField("path", aci.target+pathBuilder+pathImageAci)).Info("Importing build to rkt") hash, err := Home.Rkt.FetchInsecure(aci.target + pathBuilder + pathImageAci) if err != nil { return "", errs.WithEF(err, aci.fields, "fetch of builder aci failed") } return hash, nil }
func generateCapRetainIsolator(t *testing.T, caps ...string) appctypes.Isolator { retain, err := appctypes.NewLinuxCapabilitiesRetainSet(caps...) if err != nil { t.Fatalf("Error generating cap retain isolator", err) } return retain.AsIsolator() }
func (au *appCapsRetain) Set(s string) error { app := (*apps.Apps)(au).Last() if app == nil { return fmt.Errorf("--caps-retain must follow an image") } capsRetain, err := types.NewLinuxCapabilitiesRetainSet(strings.Split(s, ",")...) if err != nil { return err } app.CapsRetain = capsRetain return nil }
// setIsolators sets the apps' isolators according to the security context and resource spec. func setIsolators(app *appctypes.App, c *api.Container, ctx *api.SecurityContext) error { var isolators []appctypes.Isolator // Capabilities isolators. if ctx != nil { var addCaps, dropCaps []string if ctx.Capabilities != nil { addCaps, dropCaps = securitycontext.MakeCapabilities(ctx.Capabilities.Add, ctx.Capabilities.Drop) } if ctx.Privileged != nil && *ctx.Privileged { addCaps, dropCaps = allCapabilities(), []string{} } if len(addCaps) > 0 { set, err := appctypes.NewLinuxCapabilitiesRetainSet(addCaps...) if err != nil { return err } isolators = append(isolators, set.AsIsolator()) } if len(dropCaps) > 0 { set, err := appctypes.NewLinuxCapabilitiesRevokeSet(dropCaps...) if err != nil { return err } isolators = append(isolators, set.AsIsolator()) } } // Resources isolators. type resource struct { limit string request string } resources := make(map[api.ResourceName]resource) for name, quantity := range c.Resources.Limits { resources[name] = resource{limit: quantity.String()} } for name, quantity := range c.Resources.Requests { r, ok := resources[name] if !ok { r = resource{} } r.request = quantity.String() resources[name] = r } for name, res := range resources { switch name { case api.ResourceCPU: cpu, err := appctypes.NewResourceCPUIsolator(res.request, res.limit) if err != nil { return err } isolators = append(isolators, cpu.AsIsolator()) case api.ResourceMemory: memory, err := appctypes.NewResourceMemoryIsolator(res.request, res.limit) if err != nil { return err } isolators = append(isolators, memory.AsIsolator()) default: return fmt.Errorf("resource type not supported: %v", name) } } mergeIsolators(app, isolators) return nil }
func patchManifest(im *schema.ImageManifest) error { if patchName != "" { name, err := types.NewACIdentifier(patchName) if err != nil { return err } im.Name = *name } var app *types.App = im.App if patchExec != "" { if app == nil { // if the original manifest was missing an app and // patchExec is set let's assume the user is trying to // inject one... im.App = &types.App{} app = im.App } app.Exec = strings.Split(patchExec, " ") } if patchUser != "" || patchGroup != "" || patchSupplementaryGIDs != "" || patchCaps != "" || patchRevokeCaps != "" || patchMounts != "" || patchPorts != "" || patchIsolators != "" { // ...but if we still don't have an app and the user is trying // to patch one of its other parameters, it's an error if app == nil { return fmt.Errorf("no app in the supplied manifest and no exec command provided") } } if patchUser != "" { app.User = patchUser } if patchGroup != "" { app.Group = patchGroup } if patchSupplementaryGIDs != "" { app.SupplementaryGIDs = []int{} gids := strings.Split(patchSupplementaryGIDs, ",") for _, g := range gids { gid, err := strconv.Atoi(g) if err != nil { return fmt.Errorf("invalid supplementary group %q: %v", g, err) } app.SupplementaryGIDs = append(app.SupplementaryGIDs, gid) } } if patchCaps != "" { isolator := app.Isolators.GetByName(types.LinuxCapabilitiesRetainSetName) if isolator != nil { return fmt.Errorf("isolator already exists (os/linux/capabilities-retain-set)") } // Instantiate a Isolator with the content specified by the --capability // parameter. caps, err := types.NewLinuxCapabilitiesRetainSet(strings.Split(patchCaps, ",")...) if err != nil { return fmt.Errorf("cannot parse capability %q: %v", patchCaps, err) } app.Isolators = append(app.Isolators, caps.AsIsolator()) } if patchRevokeCaps != "" { isolator := app.Isolators.GetByName(types.LinuxCapabilitiesRevokeSetName) if isolator != nil { return fmt.Errorf("isolator already exists (os/linux/capabilities-remove-set)") } // Instantiate a Isolator with the content specified by the --revoke-capability // parameter. caps, err := types.NewLinuxCapabilitiesRevokeSet(strings.Split(patchRevokeCaps, ",")...) if err != nil { return fmt.Errorf("cannot parse capability %q: %v", patchRevokeCaps, err) } app.Isolators = append(app.Isolators, caps.AsIsolator()) } if patchMounts != "" { mounts := strings.Split(patchMounts, ":") for _, m := range mounts { mountPoint, err := types.MountPointFromString(m) if err != nil { return fmt.Errorf("cannot parse mount point %q: %v", m, err) } app.MountPoints = append(app.MountPoints, *mountPoint) } } if patchPorts != "" { ports := strings.Split(patchPorts, ":") for _, p := range ports { port, err := types.PortFromString(p) if err != nil { return fmt.Errorf("cannot parse port %q: %v", p, err) } app.Ports = append(app.Ports, *port) } } if patchIsolators != "" { isolators := strings.Split(patchIsolators, ":") for _, is := range isolators { name, isolatorStr, err := isolatorStrFromString(is) if err != nil { return fmt.Errorf("cannot parse isolator %q: %v", is, err) } if _, ok := types.ResourceIsolatorNames[name]; !ok { return fmt.Errorf("isolator %s is not supported for patching", name) } isolator := &types.Isolator{} if err := isolator.UnmarshalJSON([]byte(isolatorStr)); err != nil { return fmt.Errorf("cannot unmarshal isolator %v: %v", isolatorStr, err) } app.Isolators = append(app.Isolators, *isolator) } } return nil }
func patchManifest(im *schema.ImageManifest) error { if patchName != "" { name, err := types.NewACIdentifier(patchName) if err != nil { return err } im.Name = *name } var app *types.App = im.App if patchExec != "" { if app == nil { // if the original manifest was missing an app and // patchExec is set let's assume the user is trying to // inject one... im.App = &types.App{} app = im.App } app.Exec = strings.Split(patchExec, " ") } if patchUser != "" || patchGroup != "" || patchSupplementaryGIDs != "" || patchCaps != "" || patchRevokeCaps != "" || patchMounts != "" || patchPorts != "" || patchIsolators != "" { // ...but if we still don't have an app and the user is trying // to patch one of its other parameters, it's an error if app == nil { return fmt.Errorf("no app in the supplied manifest and no exec command provided") } } if patchUser != "" { app.User = patchUser } if patchGroup != "" { app.Group = patchGroup } if patchSupplementaryGIDs != "" { app.SupplementaryGIDs = []int{} gids := strings.Split(patchSupplementaryGIDs, ",") for _, g := range gids { gid, err := strconv.Atoi(g) if err != nil { return fmt.Errorf("invalid supplementary group %q: %v", g, err) } app.SupplementaryGIDs = append(app.SupplementaryGIDs, gid) } } if patchCaps != "" { isolator := app.Isolators.GetByName(types.LinuxCapabilitiesRetainSetName) if isolator != nil { return fmt.Errorf("isolator already exists (os/linux/capabilities-retain-set)") } // Instantiate a Isolator with the content specified by the --capability // parameter. caps, err := types.NewLinuxCapabilitiesRetainSet(strings.Split(patchCaps, ",")...) if err != nil { return fmt.Errorf("cannot parse capability %q: %v", patchCaps, err) } isolator, err = caps.AsIsolator() if err != nil { return err } app.Isolators = append(app.Isolators, *isolator) } if patchRevokeCaps != "" { isolator := app.Isolators.GetByName(types.LinuxCapabilitiesRevokeSetName) if isolator != nil { return fmt.Errorf("isolator already exists (os/linux/capabilities-remove-set)") } // Instantiate a Isolator with the content specified by the --revoke-capability // parameter. caps, err := types.NewLinuxCapabilitiesRevokeSet(strings.Split(patchRevokeCaps, ",")...) if err != nil { return fmt.Errorf("cannot parse capability %q: %v", patchRevokeCaps, err) } isolator, err = caps.AsIsolator() if err != nil { return err } app.Isolators = append(app.Isolators, *isolator) } if patchMounts != "" { mounts := strings.Split(patchMounts, ":") for _, m := range mounts { mountPoint, err := types.MountPointFromString(m) if err != nil { return fmt.Errorf("cannot parse mount point %q: %v", m, err) } app.MountPoints = append(app.MountPoints, *mountPoint) } } if patchPorts != "" { ports := strings.Split(patchPorts, ":") for _, p := range ports { port, err := types.PortFromString(p) if err != nil { return fmt.Errorf("cannot parse port %q: %v", p, err) } app.Ports = append(app.Ports, *port) } } // Parse seccomp args and override existing seccomp isolators if patchSeccompMode != "" { seccompIsolator, err := parseSeccompArgs(patchSeccompMode, patchSeccompSet) if err != nil { return err } seccompReps := []types.ACIdentifier{types.LinuxSeccompRemoveSetName, types.LinuxSeccompRetainSetName} app.Isolators.ReplaceIsolatorsByName(*seccompIsolator, seccompReps) } else if patchSeccompSet != "" { return fmt.Errorf("--seccomp-set specified without --seccomp-mode") } if patchIsolators != "" { isolators := strings.Split(patchIsolators, ":") for _, is := range isolators { name, isolatorStr, err := isolatorStrFromString(is) if err != nil { return fmt.Errorf("cannot parse isolator %q: %v", is, err) } _, ok := types.ResourceIsolatorNames[name] switch name { case types.LinuxNoNewPrivilegesName: ok = true kv := strings.Split(is, ",") if len(kv) != 2 { return fmt.Errorf("isolator %s: invalid format", name) } isolatorStr = fmt.Sprintf(`{ "name": "%s", "value": %s }`, name, kv[1]) case types.LinuxSeccompRemoveSetName, types.LinuxSeccompRetainSetName: ok = false } if !ok { return fmt.Errorf("isolator %s is not supported for patching", name) } isolator := &types.Isolator{} if err := isolator.UnmarshalJSON([]byte(isolatorStr)); err != nil { return fmt.Errorf("cannot unmarshal isolator %v: %v", isolatorStr, err) } app.Isolators = append(app.Isolators, *isolator) } } return nil }
// The list of default capabilities inside systemd-nspawn pod is available // here: https://www.freedesktop.org/software/systemd/man/systemd-nspawn.html nspawnCapabilities, _ = types.NewLinuxCapabilitiesRetainSet([]string{ "CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_DAC_READ_SEARCH", "CAP_FOWNER", "CAP_FSETID", "CAP_IPC_OWNER", "CAP_KILL", "CAP_LEASE", "CAP_LINUX_IMMUTABLE", "CAP_NET_BIND_SERVICE", "CAP_NET_BROADCAST", "CAP_NET_RAW", "CAP_SETGID", "CAP_SETFCAP", "CAP_SETPCAP", "CAP_SETUID", "CAP_SYS_ADMIN", "CAP_SYS_CHROOT", "CAP_SYS_NICE", "CAP_SYS_PTRACE", "CAP_SYS_TTY_CONFIG", "CAP_SYS_RESOURCE", "CAP_SYS_BOOT", "CAP_AUDIT_WRITE", "CAP_AUDIT_CONTROL", "CAP_MKNOD", }...) )