mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
daemon: add a flag to override the default seccomp profile
Signed-off-by: Antonio Murdaca <runcom@redhat.com>
This commit is contained in:
parent
ecd806cdf1
commit
b237189e6c
15 changed files with 150 additions and 23 deletions
|
@ -42,10 +42,20 @@ func (s *systemRouter) getInfo(ctx context.Context, w http.ResponseWriter, r *ht
|
|||
if versions.LessThan(httputils.VersionFromContext(ctx), "1.25") {
|
||||
// TODO: handle this conversion in engine-api
|
||||
type oldInfo struct {
|
||||
*types.Info
|
||||
*types.InfoBase
|
||||
ExecutionDriver string
|
||||
SecurityOptions []string
|
||||
}
|
||||
return httputils.WriteJSON(w, http.StatusOK, &oldInfo{Info: info, ExecutionDriver: "<not supported>"})
|
||||
old := &oldInfo{
|
||||
InfoBase: info.InfoBase,
|
||||
ExecutionDriver: "<not supported>",
|
||||
}
|
||||
for _, s := range info.SecurityOptions {
|
||||
if s.Key == "Name" {
|
||||
old.SecurityOptions = append(old.SecurityOptions, s.Value)
|
||||
}
|
||||
}
|
||||
return httputils.WriteJSON(w, http.StatusOK, old)
|
||||
}
|
||||
return httputils.WriteJSON(w, http.StatusOK, info)
|
||||
}
|
||||
|
|
|
@ -142,9 +142,9 @@ type Version struct {
|
|||
BuildTime string `json:",omitempty"`
|
||||
}
|
||||
|
||||
// Info contains response of Remote API:
|
||||
// InfoBase contains the base response of Remote API:
|
||||
// GET "/info"
|
||||
type Info struct {
|
||||
type InfoBase struct {
|
||||
ID string
|
||||
Containers int
|
||||
ContainersRunning int
|
||||
|
@ -191,7 +191,6 @@ type Info struct {
|
|||
ServerVersion string
|
||||
ClusterStore string
|
||||
ClusterAdvertise string
|
||||
SecurityOptions []string
|
||||
Runtimes map[string]Runtime
|
||||
DefaultRuntime string
|
||||
Swarm swarm.Info
|
||||
|
@ -202,6 +201,18 @@ type Info struct {
|
|||
Isolation container.Isolation
|
||||
}
|
||||
|
||||
// SecurityOpt holds key/value pair about a security option
|
||||
type SecurityOpt struct {
|
||||
Key, Value string
|
||||
}
|
||||
|
||||
// Info contains response of Remote API:
|
||||
// GET "/info"
|
||||
type Info struct {
|
||||
*InfoBase
|
||||
SecurityOptions []SecurityOpt
|
||||
}
|
||||
|
||||
// PluginsInfo is a temp struct holding Plugins name
|
||||
// registered with docker daemon. It is used by Info struct
|
||||
type PluginsInfo struct {
|
||||
|
|
|
@ -140,9 +140,20 @@ func prettyPrintInfo(dockerCli *command.DockerCli, info types.Info) error {
|
|||
}
|
||||
|
||||
if info.OSType == "linux" {
|
||||
fmt.Fprintf(dockerCli.Out(), "Security Options:")
|
||||
ioutils.FprintfIfNotEmpty(dockerCli.Out(), " %s", strings.Join(info.SecurityOptions, " "))
|
||||
fmt.Fprintf(dockerCli.Out(), "\n")
|
||||
if len(info.SecurityOptions) != 0 {
|
||||
fmt.Fprintf(dockerCli.Out(), "Security Options:\n")
|
||||
for _, o := range info.SecurityOptions {
|
||||
switch o.Key {
|
||||
case "Name":
|
||||
fmt.Fprintf(dockerCli.Out(), " %s\n", o.Value)
|
||||
case "Profile":
|
||||
if o.Key != "default" {
|
||||
fmt.Fprintf(dockerCli.Err(), " WARNING: You're not using the Docker's default seccomp profile\n")
|
||||
}
|
||||
fmt.Fprintf(dockerCli.Out(), " %s: %s\n", o.Key, o.Value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Isolation only has meaning on a Windows daemon.
|
||||
|
|
|
@ -46,8 +46,10 @@ func TestInfo(t *testing.T) {
|
|||
return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL)
|
||||
}
|
||||
info := &types.Info{
|
||||
InfoBase: &types.InfoBase{
|
||||
ID: "daemonID",
|
||||
Containers: 3,
|
||||
},
|
||||
}
|
||||
b, err := json.Marshal(info)
|
||||
if err != nil {
|
||||
|
|
|
@ -39,6 +39,7 @@ type Config struct {
|
|||
OOMScoreAdjust int `json:"oom-score-adjust,omitempty"`
|
||||
Init bool `json:"init,omitempty"`
|
||||
InitPath string `json:"init-path,omitempty"`
|
||||
SeccompProfile string `json:"seccomp-profile,omitempty"`
|
||||
}
|
||||
|
||||
// bridgeConfig stores all the bridge driver specific
|
||||
|
@ -101,6 +102,7 @@ func (config *Config) InstallFlags(flags *pflag.FlagSet) {
|
|||
flags.StringVar(&config.InitPath, "init-path", "", "Path to the docker-init binary")
|
||||
flags.Int64Var(&config.CPURealtimePeriod, "cpu-rt-period", 0, "Limit the CPU real-time period in microseconds")
|
||||
flags.Int64Var(&config.CPURealtimeRuntime, "cpu-rt-runtime", 0, "Limit the CPU real-time runtime in microseconds")
|
||||
flags.StringVar(&config.SeccompProfile, "seccomp-profile", "", "Path to seccomp profile")
|
||||
|
||||
config.attachExperimentalFlags(flags)
|
||||
}
|
||||
|
|
|
@ -104,6 +104,9 @@ type Daemon struct {
|
|||
defaultIsolation containertypes.Isolation // Default isolation mode on Windows
|
||||
clusterProvider cluster.Provider
|
||||
cluster Cluster
|
||||
|
||||
seccompProfile []byte
|
||||
seccompProfilePath string
|
||||
}
|
||||
|
||||
// HasExperimental returns whether the experimental features of the daemon are enabled or not
|
||||
|
@ -530,6 +533,10 @@ func NewDaemon(config *Config, registryService registry.Service, containerdRemot
|
|||
}
|
||||
}()
|
||||
|
||||
if err := d.setupSeccompProfile(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Set the default isolation mode (only applicable on Windows)
|
||||
if err := d.setDefaultIsolation(); err != nil {
|
||||
return nil, fmt.Errorf("error setting default isolation mode: %v", err)
|
||||
|
|
|
@ -177,3 +177,7 @@ func setupDaemonProcess(config *Config) error {
|
|||
func (daemon *Daemon) verifyVolumesInfo(container *container.Container) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (daemon *Daemon) setupSeccompProfile() error {
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ package daemon
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
|
@ -1242,6 +1243,23 @@ func (daemon *Daemon) initCgroupsPath(path string) error {
|
|||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (daemon *Daemon) setupSeccompProfile() error {
|
||||
if daemon.configStore.SeccompProfile != "" {
|
||||
daemon.seccompProfilePath = daemon.configStore.SeccompProfile
|
||||
b, err := ioutil.ReadFile(daemon.configStore.SeccompProfile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("opening seccomp profile (%s) failed: %v", daemon.configStore.SeccompProfile, err)
|
||||
}
|
||||
daemon.seccompProfile = b
|
||||
p := struct {
|
||||
DefaultAction string `json:"defaultAction"`
|
||||
}{}
|
||||
if err := json.Unmarshal(daemon.seccompProfile, &p); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -532,3 +532,7 @@ func setupDaemonProcess(config *Config) error {
|
|||
func (daemon *Daemon) verifyVolumesInfo(container *container.Container) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (daemon *Daemon) setupSeccompProfile() error {
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -68,22 +68,29 @@ func (daemon *Daemon) SystemInfo() (*types.Info, error) {
|
|||
}
|
||||
})
|
||||
|
||||
var securityOptions []string
|
||||
securityOptions := []types.SecurityOpt{}
|
||||
if sysInfo.AppArmor {
|
||||
securityOptions = append(securityOptions, "apparmor")
|
||||
securityOptions = append(securityOptions, types.SecurityOpt{Key: "Name", Value: "apparmor"})
|
||||
}
|
||||
if sysInfo.Seccomp && supportsSeccomp {
|
||||
securityOptions = append(securityOptions, "seccomp")
|
||||
profile := daemon.seccompProfilePath
|
||||
if profile == "" {
|
||||
profile = "default"
|
||||
}
|
||||
securityOptions = append(securityOptions,
|
||||
types.SecurityOpt{Key: "Name", Value: "seccomp"},
|
||||
types.SecurityOpt{Key: "Profile", Value: profile},
|
||||
)
|
||||
}
|
||||
if selinuxEnabled() {
|
||||
securityOptions = append(securityOptions, "selinux")
|
||||
securityOptions = append(securityOptions, types.SecurityOpt{Key: "Name", Value: "selinux"})
|
||||
}
|
||||
uid, gid := daemon.GetRemappedUIDGID()
|
||||
if uid != 0 || gid != 0 {
|
||||
securityOptions = append(securityOptions, "userns")
|
||||
securityOptions = append(securityOptions, types.SecurityOpt{Key: "Name", Value: "userns"})
|
||||
}
|
||||
|
||||
v := &types.Info{
|
||||
v := &types.InfoBase{
|
||||
ID: daemon.ID,
|
||||
Containers: int(cRunning + cPaused + cStopped),
|
||||
ContainersRunning: int(cRunning),
|
||||
|
@ -120,7 +127,6 @@ func (daemon *Daemon) SystemInfo() (*types.Info, error) {
|
|||
HTTPProxy: sockets.GetProxyEnv("http_proxy"),
|
||||
HTTPSProxy: sockets.GetProxyEnv("https_proxy"),
|
||||
NoProxy: sockets.GetProxyEnv("no_proxy"),
|
||||
SecurityOptions: securityOptions,
|
||||
LiveRestoreEnabled: daemon.configStore.LiveRestoreEnabled,
|
||||
Isolation: daemon.defaultIsolation,
|
||||
}
|
||||
|
@ -150,7 +156,12 @@ func (daemon *Daemon) SystemInfo() (*types.Info, error) {
|
|||
}
|
||||
v.Name = hostname
|
||||
|
||||
return v, nil
|
||||
i := &types.Info{
|
||||
InfoBase: v,
|
||||
SecurityOptions: securityOptions,
|
||||
}
|
||||
|
||||
return i, nil
|
||||
}
|
||||
|
||||
// SystemVersion returns version information about the daemon.
|
||||
|
|
|
@ -36,12 +36,19 @@ func setSeccomp(daemon *Daemon, rs *specs.Spec, c *container.Container) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if daemon.seccompProfile != nil {
|
||||
profile, err = seccomp.LoadProfile(string(daemon.seccompProfile), rs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
profile, err = seccomp.GetDefaultProfile(rs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rs.Linux.Seccomp = profile
|
||||
return nil
|
||||
|
|
|
@ -74,6 +74,7 @@ Options:
|
|||
-p, --pidfile string Path to use for daemon PID file (default "/var/run/docker.pid")
|
||||
--raw-logs Full timestamps without ANSI coloring
|
||||
--registry-mirror value Preferred Docker registry mirror (default [])
|
||||
--seccomp-profile value Path to seccomp profile
|
||||
--selinux-enabled Enable selinux support
|
||||
--shutdown-timeout=15 Set the shutdown timeout value in seconds
|
||||
-s, --storage-driver string Storage driver to use
|
||||
|
@ -1195,6 +1196,7 @@ This is a full example of the allowed configuration options on Linux:
|
|||
"icc": false,
|
||||
"raw-logs": false,
|
||||
"registry-mirrors": [],
|
||||
"seccomp-profile": "",
|
||||
"insecure-registries": [],
|
||||
"disable-legacy-registry": false,
|
||||
"default-runtime": "runc",
|
||||
|
|
|
@ -11,5 +11,5 @@ func (s *DockerSuite) TestInfoSecurityOptions(c *check.C) {
|
|||
testRequires(c, SameHostDaemon, seccompEnabled, Apparmor, DaemonIsLinux)
|
||||
|
||||
out, _ := dockerCmd(c, "info")
|
||||
c.Assert(out, checker.Contains, "Security Options: apparmor seccomp")
|
||||
c.Assert(out, checker.Contains, "Security Options:\n apparmor\n seccomp\n Profile: default\n")
|
||||
}
|
||||
|
|
|
@ -1375,3 +1375,37 @@ func (s *DockerDaemonSuite) TestRunSeccompJSONNoArchAndArchMap(c *check.C) {
|
|||
c.Assert(err, check.NotNil)
|
||||
c.Assert(out, checker.Contains, "'architectures' and 'archMap' were specified in the seccomp profile, use either 'architectures' or 'archMap'")
|
||||
}
|
||||
|
||||
func (s *DockerDaemonSuite) TestRunWithDaemonDefaultSeccompProfile(c *check.C) {
|
||||
testRequires(c, SameHostDaemon, seccompEnabled)
|
||||
|
||||
err := s.d.StartWithBusybox()
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
// 1) verify I can run containers with the Docker default shipped profile which allows chmod
|
||||
_, err = s.d.Cmd("run", "busybox", "chmod", "777", ".")
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
jsonData := `{
|
||||
"defaultAction": "SCMP_ACT_ALLOW",
|
||||
"syscalls": [
|
||||
{
|
||||
"name": "chmod",
|
||||
"action": "SCMP_ACT_ERRNO"
|
||||
}
|
||||
]
|
||||
}`
|
||||
tmpFile, err := ioutil.TempFile("", "profile.json")
|
||||
c.Assert(err, check.IsNil)
|
||||
defer tmpFile.Close()
|
||||
_, err = tmpFile.Write([]byte(jsonData))
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
// 2) restart the daemon and add a custom seccomp profile in which we deny chmod
|
||||
err = s.d.Restart("--seccomp-profile=" + tmpFile.Name())
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
out, err := s.d.Cmd("run", "busybox", "chmod", "777", ".")
|
||||
c.Assert(err, check.NotNil)
|
||||
c.Assert(out, checker.Contains, "Operation not permitted")
|
||||
}
|
||||
|
|
|
@ -56,6 +56,7 @@ dockerd - Enable daemon mode
|
|||
[**--raw-logs**]
|
||||
[**--registry-mirror**[=*[]*]]
|
||||
[**-s**|**--storage-driver**[=*STORAGE-DRIVER*]]
|
||||
[**--seccomp-profile**[=*SECCOMP-PROFILE-PATH*]]
|
||||
[**--selinux-enabled**]
|
||||
[**--shutdown-timeout**[=*15*]]
|
||||
[**--storage-opt**[=*[]*]]
|
||||
|
@ -248,6 +249,9 @@ output otherwise.
|
|||
**-s**, **--storage-driver**=""
|
||||
Force the Docker runtime to use a specific storage driver.
|
||||
|
||||
**--seccomp-profile**=""
|
||||
Path to seccomp profile.
|
||||
|
||||
**--selinux-enabled**=*true*|*false*
|
||||
Enable selinux support. Default is false.
|
||||
|
||||
|
|
Loading…
Reference in a new issue