瀏覽代碼

Merge pull request #46386 from dperny/add-swarm-seccomp-apparmor

Add support for swarm seccomp and apparmor
Sebastiaan van Stijn 1 年之前
父節點
當前提交
b94e88c1e2

+ 9 - 0
api/server/router/swarm/helpers.go

@@ -118,4 +118,13 @@ func adjustForAPIVersion(cliVersion string, service *swarm.ServiceSpec) {
 		service.Mode.ReplicatedJob = nil
 		service.Mode.GlobalJob = nil
 	}
+
+	if versions.LessThan(cliVersion, "1.44") {
+		// seccomp, apparmor, and no_new_privs were added in 1.44.
+		if service.TaskTemplate.ContainerSpec != nil && service.TaskTemplate.ContainerSpec.Privileges != nil {
+			service.TaskTemplate.ContainerSpec.Privileges.Seccomp = nil
+			service.TaskTemplate.ContainerSpec.Privileges.AppArmor = nil
+			service.TaskTemplate.ContainerSpec.Privileges.NoNewPrivileges = false
+		}
+	}
 }

+ 26 - 0
api/swagger.yaml

@@ -3553,6 +3553,32 @@ definitions:
                   Level:
                     type: "string"
                     description: "SELinux level label"
+              Seccomp:
+                type: "object"
+                description: "Options for configuring seccomp on the container"
+                properties:
+                  Mode:
+                    type: "string"
+                    enum:
+                      - "default"
+                      - "unconfined"
+                      - "custom"
+                  Profile:
+                    description: "The custom seccomp profile as a json object"
+                    type: "string"
+              AppArmor:
+                type: "object"
+                description: "Options for configuring AppArmor on the container"
+                properties:
+                  Mode:
+                    type: "string"
+                    enum:
+                      - "default"
+                      - "disabled"
+              NoNewPrivileges:
+                type: "boolean"
+                description: "Configuration of the no_new_privs bit in the container"
+
           TTY:
             description: "Whether a pseudo-TTY should be allocated."
             type: "boolean"

+ 41 - 2
api/types/swarm/container.go

@@ -32,6 +32,42 @@ type SELinuxContext struct {
 	Level string
 }
 
+// SeccompMode is the type used for the enumeration of possible seccomp modes
+// in SeccompOpts
+type SeccompMode string
+
+const (
+	SeccompModeDefault    SeccompMode = "default"
+	SeccompModeUnconfined SeccompMode = "unconfined"
+	SeccompModeCustom     SeccompMode = "custom"
+)
+
+// SeccompOpts defines the options for configuring seccomp on a swarm-managed
+// container.
+type SeccompOpts struct {
+	// Mode is the SeccompMode used for the container.
+	Mode SeccompMode `json:",omitempty"`
+	// Profile is the custom seccomp profile as a json object to be used with
+	// the container. Mode should be set to SeccompModeCustom when using a
+	// custom profile in this manner.
+	Profile []byte `json:",omitempty"`
+}
+
+// AppArmorMode is type used for the enumeration of possible AppArmor modes in
+// AppArmorOpts
+type AppArmorMode string
+
+const (
+	AppArmorModeDefault  AppArmorMode = "default"
+	AppArmorModeDisabled AppArmorMode = "disabled"
+)
+
+// AppArmorOpts defines the options for configuring AppArmor on a swarm-managed
+// container.  Currently, custom AppArmor profiles are not supported.
+type AppArmorOpts struct {
+	Mode AppArmorMode `json:",omitempty"`
+}
+
 // CredentialSpec for managed service account (Windows only)
 type CredentialSpec struct {
 	Config   string
@@ -41,8 +77,11 @@ type CredentialSpec struct {
 
 // Privileges defines the security options for the container.
 type Privileges struct {
-	CredentialSpec *CredentialSpec
-	SELinuxContext *SELinuxContext
+	CredentialSpec  *CredentialSpec
+	SELinuxContext  *SELinuxContext
+	Seccomp         *SeccompOpts  `json:",omitempty"`
+	AppArmor        *AppArmorOpts `json:",omitempty"`
+	NoNewPrivileges bool
 }
 
 // ContainerSpec represents the spec of a container.

+ 56 - 0
daemon/cluster/convert/container.go

@@ -69,6 +69,34 @@ func containerSpecFromGRPC(c *swarmapi.ContainerSpec) *types.ContainerSpec {
 				Level:   c.Privileges.SELinuxContext.Level,
 			}
 		}
+
+		if c.Privileges.Seccomp != nil {
+			containerSpec.Privileges.Seccomp = &types.SeccompOpts{
+				Profile: c.Privileges.Seccomp.Profile,
+			}
+
+			switch c.Privileges.Seccomp.Mode {
+			case swarmapi.Privileges_SeccompOpts_DEFAULT:
+				containerSpec.Privileges.Seccomp.Mode = types.SeccompModeDefault
+			case swarmapi.Privileges_SeccompOpts_UNCONFINED:
+				containerSpec.Privileges.Seccomp.Mode = types.SeccompModeUnconfined
+			case swarmapi.Privileges_SeccompOpts_CUSTOM:
+				containerSpec.Privileges.Seccomp.Mode = types.SeccompModeCustom
+			}
+		}
+
+		if c.Privileges.Apparmor != nil {
+			containerSpec.Privileges.AppArmor = &types.AppArmorOpts{}
+
+			switch c.Privileges.Apparmor.Mode {
+			case swarmapi.Privileges_AppArmorOpts_DEFAULT:
+				containerSpec.Privileges.AppArmor.Mode = types.AppArmorModeDefault
+			case swarmapi.Privileges_AppArmorOpts_DISABLED:
+				containerSpec.Privileges.AppArmor.Mode = types.AppArmorModeDisabled
+			}
+		}
+
+		containerSpec.Privileges.NoNewPrivileges = c.Privileges.NoNewPrivileges
 	}
 
 	// Mounts
@@ -308,6 +336,34 @@ func containerToGRPC(c *types.ContainerSpec) (*swarmapi.ContainerSpec, error) {
 				Level:   c.Privileges.SELinuxContext.Level,
 			}
 		}
+
+		if c.Privileges.Seccomp != nil {
+			containerSpec.Privileges.Seccomp = &swarmapi.Privileges_SeccompOpts{
+				Profile: c.Privileges.Seccomp.Profile,
+			}
+
+			switch c.Privileges.Seccomp.Mode {
+			case types.SeccompModeDefault:
+				containerSpec.Privileges.Seccomp.Mode = swarmapi.Privileges_SeccompOpts_DEFAULT
+			case types.SeccompModeUnconfined:
+				containerSpec.Privileges.Seccomp.Mode = swarmapi.Privileges_SeccompOpts_UNCONFINED
+			case types.SeccompModeCustom:
+				containerSpec.Privileges.Seccomp.Mode = swarmapi.Privileges_SeccompOpts_CUSTOM
+			}
+		}
+
+		if c.Privileges.AppArmor != nil {
+			containerSpec.Privileges.Apparmor = &swarmapi.Privileges_AppArmorOpts{}
+
+			switch c.Privileges.AppArmor.Mode {
+			case types.AppArmorModeDefault:
+				containerSpec.Privileges.Apparmor.Mode = swarmapi.Privileges_AppArmorOpts_DEFAULT
+			case types.AppArmorModeDisabled:
+				containerSpec.Privileges.Apparmor.Mode = swarmapi.Privileges_AppArmorOpts_DISABLED
+			}
+		}
+
+		containerSpec.Privileges.NoNewPrivileges = c.Privileges.NoNewPrivileges
 	}
 
 	if c.Configs != nil {

+ 26 - 0
daemon/cluster/executor/container/container.go

@@ -698,6 +698,32 @@ func (c *containerConfig) applyPrivileges(hc *enginecontainer.HostConfig) {
 			hc.SecurityOpt = append(hc.SecurityOpt, "label=type:"+selinux.Type)
 		}
 	}
+
+	// variable to make the lines shorter and easier to read
+	if seccomp := privileges.Seccomp; seccomp != nil {
+		switch seccomp.Mode {
+		// case api.Privileges_SeccompOpts_DEFAULT:
+		//   if the setting is default, nothing needs to be set here. we leave
+		//   the option empty.
+		case api.Privileges_SeccompOpts_UNCONFINED:
+			hc.SecurityOpt = append(hc.SecurityOpt, "seccomp=unconfined")
+		case api.Privileges_SeccompOpts_CUSTOM:
+			// Profile is bytes, but those bytes are actually a string. This is
+			// basically verbatim what happens in the cli after a file is read.
+			hc.SecurityOpt = append(hc.SecurityOpt, fmt.Sprintf("seccomp=%s", seccomp.Profile))
+		}
+	}
+
+	// if the setting is DEFAULT, then nothing to be done. If it's DISABLED,
+	// we set that. Custom not supported yet. When custom *is* supported, make
+	// it look like the above.
+	if apparmor := privileges.Apparmor; apparmor != nil && apparmor.Mode == api.Privileges_AppArmorOpts_DISABLED {
+		hc.SecurityOpt = append(hc.SecurityOpt, "apparmor=unconfined")
+	}
+
+	if privileges.NoNewPrivileges {
+		hc.SecurityOpt = append(hc.SecurityOpt, "no-new-privileges=true")
+	}
 }
 
 func (c *containerConfig) eventFilter() filters.Args {

+ 3 - 0
docs/api/version-history.md

@@ -52,6 +52,9 @@ keywords: "API, Docker, rcli, REST, documentation"
   These endpoints will also return the full set of validation errors they find,
   instead of returning only the first one.
   Note that this change is _unversioned_ and applies to all API versions.
+* `POST /services/create` and `POST /services/{id}/update` now accept `Seccomp`
+  and `AppArmor` fields in the `ContainerSpec.Privileges` object. This allows
+  some configuration of Seccomp and AppArmor in Swarm services.
 
 ## v1.43 API changes
 

+ 1 - 1
vendor.mod

@@ -66,7 +66,7 @@ require (
 	github.com/moby/locker v1.0.1
 	github.com/moby/patternmatcher v0.6.0
 	github.com/moby/pubsub v1.0.0
-	github.com/moby/swarmkit/v2 v2.0.0-20230815220644-3f2e40b3ed51
+	github.com/moby/swarmkit/v2 v2.0.0-20230823155524-12f0c246fed0
 	github.com/moby/sys/mount v0.3.3
 	github.com/moby/sys/mountinfo v0.6.2
 	github.com/moby/sys/sequential v0.5.0

+ 2 - 2
vendor.sum

@@ -917,8 +917,8 @@ github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkV
 github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
 github.com/moby/pubsub v1.0.0 h1:jkp/imWsmJz2f6LyFsk7EkVeN2HxR/HTTOY8kHrsxfA=
 github.com/moby/pubsub v1.0.0/go.mod h1:bXSO+3h5MNXXCaEG+6/NlAIk7MMZbySZlnB+cUQhKKc=
-github.com/moby/swarmkit/v2 v2.0.0-20230815220644-3f2e40b3ed51 h1:Am1RXolTCcQT5zaEUBGczaHZaV069crCKpLHckp9isM=
-github.com/moby/swarmkit/v2 v2.0.0-20230815220644-3f2e40b3ed51/go.mod h1:dHTjRFlamMrutFg1Vi0AEZKtVx2qZV/7A/imviPXQiE=
+github.com/moby/swarmkit/v2 v2.0.0-20230823155524-12f0c246fed0 h1:DBx1xD69N0nQjoMQskoTQQTb0hpZbo+8Rk9ug0wUMKs=
+github.com/moby/swarmkit/v2 v2.0.0-20230823155524-12f0c246fed0/go.mod h1:dHTjRFlamMrutFg1Vi0AEZKtVx2qZV/7A/imviPXQiE=
 github.com/moby/sys/mount v0.1.0/go.mod h1:FVQFLDRWwyBjDTBNQXDlWnSFREqOo3OKX9aqhmeoo74=
 github.com/moby/sys/mount v0.1.1/go.mod h1:FVQFLDRWwyBjDTBNQXDlWnSFREqOo3OKX9aqhmeoo74=
 github.com/moby/sys/mount v0.3.3 h1:fX1SVkXFJ47XWDoeFW4Sq7PdQJnV2QIDZAqjNqgEjUs=

+ 78 - 0
vendor/github.com/moby/swarmkit/v2/api/api.pb.txt

@@ -4324,6 +4324,29 @@ file {
       }
       json_name: "selinuxContext"
     }
+    field {
+      name: "seccomp"
+      number: 3
+      label: LABEL_OPTIONAL
+      type: TYPE_MESSAGE
+      type_name: ".docker.swarmkit.v1.Privileges.SeccompOpts"
+      json_name: "seccomp"
+    }
+    field {
+      name: "apparmor"
+      number: 4
+      label: LABEL_OPTIONAL
+      type: TYPE_MESSAGE
+      type_name: ".docker.swarmkit.v1.Privileges.AppArmorOpts"
+      json_name: "apparmor"
+    }
+    field {
+      name: "no_new_privileges"
+      number: 5
+      label: LABEL_OPTIONAL
+      type: TYPE_BOOL
+      json_name: "noNewPrivileges"
+    }
     nested_type {
       name: "CredentialSpec"
       field {
@@ -4392,6 +4415,61 @@ file {
         json_name: "level"
       }
     }
+    nested_type {
+      name: "SeccompOpts"
+      field {
+        name: "mode"
+        number: 1
+        label: LABEL_OPTIONAL
+        type: TYPE_ENUM
+        type_name: ".docker.swarmkit.v1.Privileges.SeccompOpts.SeccompMode"
+        json_name: "mode"
+      }
+      field {
+        name: "profile"
+        number: 2
+        label: LABEL_OPTIONAL
+        type: TYPE_BYTES
+        json_name: "profile"
+      }
+      enum_type {
+        name: "SeccompMode"
+        value {
+          name: "DEFAULT"
+          number: 0
+        }
+        value {
+          name: "UNCONFINED"
+          number: 1
+        }
+        value {
+          name: "CUSTOM"
+          number: 2
+        }
+      }
+    }
+    nested_type {
+      name: "AppArmorOpts"
+      field {
+        name: "mode"
+        number: 1
+        label: LABEL_OPTIONAL
+        type: TYPE_ENUM
+        type_name: ".docker.swarmkit.v1.Privileges.AppArmorOpts.AppArmorMode"
+        json_name: "mode"
+      }
+      enum_type {
+        name: "AppArmorMode"
+        value {
+          name: "DEFAULT"
+          number: 0
+        }
+        value {
+          name: "DISABLED"
+          number: 1
+        }
+      }
+    }
   }
   message_type {
     name: "JobStatus"

文件差異過大導致無法顯示
+ 564 - 402
vendor/github.com/moby/swarmkit/v2/api/types.pb.go


+ 33 - 0
vendor/github.com/moby/swarmkit/v2/api/types.proto

@@ -1156,6 +1156,39 @@ message Privileges {
 		string level = 5;
 	}
 	SELinuxContext selinux_context = 2 [(gogoproto.customname) = "SELinuxContext"];
+
+	// SeccompOpts contains options for configuring seccomp profiles on the
+	// container. See https://docs.docker.com/engine/security/seccomp/ for more
+	// information.
+	message SeccompOpts {
+		enum SeccompMode {
+			DEFAULT = 0;
+			UNCONFINED = 1;
+			CUSTOM =  2;
+		}
+		SeccompMode mode = 1;
+		// Profile contains the json definition of the seccomp profile to use,
+		// if Mode is set to custom.
+		bytes profile = 2;
+	}
+	SeccompOpts seccomp = 3;
+
+	// AppArmorOpts contains options for configuring AppArmor profiles on the
+	// container. Currently, custom profiles are not supported. See
+	// https://docs.docker.com/engine/security/apparmor/ for more information.
+	message AppArmorOpts {
+		enum AppArmorMode {
+			DEFAULT = 0;
+			DISABLED = 1;
+		}
+		AppArmorMode mode = 1;
+	}
+	AppArmorOpts apparmor = 4;
+
+	// NoNewPrivileges, if set to true, disables the container from gaining new
+	// privileges. See https://docs.kernel.org/userspace-api/no_new_privs.html
+	// for details.
+	bool no_new_privileges = 5;
 }
 
 // JobStatus indicates the status of a Service that is in one of the Job modes.

+ 1 - 1
vendor/modules.txt

@@ -829,7 +829,7 @@ github.com/moby/patternmatcher/ignorefile
 # github.com/moby/pubsub v1.0.0
 ## explicit; go 1.19
 github.com/moby/pubsub
-# github.com/moby/swarmkit/v2 v2.0.0-20230815220644-3f2e40b3ed51
+# github.com/moby/swarmkit/v2 v2.0.0-20230823155524-12f0c246fed0
 ## explicit; go 1.18
 github.com/moby/swarmkit/v2/agent
 github.com/moby/swarmkit/v2/agent/configs

部分文件因文件數量過多而無法顯示