daemon: add a flag to override the default seccomp profile

Signed-off-by: Antonio Murdaca <runcom@redhat.com>
This commit is contained in:
Antonio Murdaca 2016-09-02 15:20:54 +02:00
parent ecd806cdf1
commit b237189e6c
No known key found for this signature in database
GPG Key ID: B2BEAD150DE936B9
15 changed files with 150 additions and 23 deletions

View File

@ -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)
}

View File

@ -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 {

View File

@ -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.

View File

@ -46,8 +46,10 @@ func TestInfo(t *testing.T) {
return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL)
}
info := &types.Info{
ID: "daemonID",
Containers: 3,
InfoBase: &types.InfoBase{
ID: "daemonID",
Containers: 3,
},
}
b, err := json.Marshal(info)
if err != nil {

View File

@ -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)
}

View File

@ -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)

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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.

View File

@ -37,9 +37,16 @@ func setSeccomp(daemon *Daemon, rs *specs.Spec, c *container.Container) error {
return err
}
} else {
profile, err = seccomp.GetDefaultProfile(rs)
if err != nil {
return err
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
}
}
}

View File

@ -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",

View File

@ -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")
}

View File

@ -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")
}

View File

@ -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.