[lxc-devel] [lxd/master] PKI mode and some fixes

stgraber on Github lxc-bot at linuxcontainers.org
Wed Jun 1 22:55:15 UTC 2016


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 301 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20160601/c69d4284/attachment.bin>
-------------- next part --------------
From f636e5f89364ba5491c3125ca111106bd4850ff6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Fri, 27 May 2016 20:07:48 -0400
Subject: [PATCH 1/3] Fix parsing of <FQDN>:<PORT>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 lxc/remote.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lxc/remote.go b/lxc/remote.go
index e5573b5..a01b0f6 100644
--- a/lxc/remote.go
+++ b/lxc/remote.go
@@ -113,7 +113,7 @@ func (c *remoteCmd) addServer(config *lxd.Config, server string, addr string, ac
 
 	// Fix broken URL parser
 	if !strings.Contains(addr, "://") && remoteURL.Scheme != "" && remoteURL.Scheme != "unix" && remoteURL.Host == "" {
-		remoteURL.Host = remoteURL.Scheme
+		remoteURL.Host = addr
 		remoteURL.Scheme = ""
 	}
 

From 9bdd37997a279a259e8d99e3b3ebfe311dcb1dad Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Fri, 13 May 2016 22:51:48 -0400
Subject: [PATCH 2/3] Implement PKI authentication
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This adds support for enteprise PKI mode where a central Certificate
Authority is used to issue certificates for the LXD daemons as well as
the clients.

To enable this, replace or add the following files on the daemon side:
 - server.crt (CA generated server certificate)
 - server.key (key for the above certificate)
 - server.ca (Certificate Authority root certificate)

And on the client side:
 - client.crt (CA generated client certificate)
 - client.key (key for the above certificate)
 - client.ca (Certificate Authority root certificate)

In such mode, only clients using certificates issued by the PKI will be
able to connect. Normal password authentication is still used on first
handshake.

Closes #1985

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 client.go                     | 19 ++++++++++++++++---
 doc/lxd-ssl-authentication.md | 13 +++++++++++--
 lxc/remote.go                 |  2 +-
 lxd/api_1.0.go                |  8 ++++++++
 lxd/containers_post.go        |  2 +-
 lxd/daemon.go                 | 26 ++++++++++++++++++++++----
 lxd/images.go                 |  2 +-
 shared/network.go             | 29 ++++++++++++++++++++++++++---
 shared/simplestreams.go       |  2 +-
 9 files changed, 87 insertions(+), 16 deletions(-)

diff --git a/client.go b/client.go
index 213b9cb..db12ed0 100644
--- a/client.go
+++ b/client.go
@@ -186,6 +186,17 @@ func NewClient(config *Config, remote string) (*Client, error) {
 			info.ClientPEMKey = string(keyBytes)
 		}
 
+		// Read the client key (if it exists)
+		clientCaPath := path.Join(config.ConfigDir, "client.ca")
+		if shared.PathExists(clientCaPath) {
+			caBytes, err := ioutil.ReadFile(clientCaPath)
+			if err != nil {
+				return nil, err
+			}
+
+			info.ClientPEMCa = string(caBytes)
+		}
+
 		// Read the server certificate (if it exists)
 		serverCertPath := config.ServerCertPath(remote)
 		if shared.PathExists(serverCertPath) {
@@ -222,6 +233,8 @@ type ConnectInfo struct {
 	ClientPEMCert string
 	// ClientPEMKey is the PEM encoded private bytes of the client's key associated with its certificate
 	ClientPEMKey string
+	// ClientPEMCa is the PEM encoded client certificate authority (if any)
+	ClientPEMCa string
 	// ServerPEMCert is the PEM encoded server certificate that we are
 	// connecting to. It can be the empty string if we do not know the
 	// server's certificate yet.
@@ -264,8 +277,8 @@ func connectViaUnix(c *Client, remote *RemoteConfig) error {
 	return nil
 }
 
-func connectViaHttp(c *Client, remote *RemoteConfig, clientCert, clientKey, serverCert string) error {
-	tlsconfig, err := shared.GetTLSConfigMem(clientCert, clientKey, serverCert)
+func connectViaHttp(c *Client, remote *RemoteConfig, clientCert, clientKey, clientCA, serverCert string) error {
+	tlsconfig, err := shared.GetTLSConfigMem(clientCert, clientKey, clientCA, serverCert)
 	if err != nil {
 		return err
 	}
@@ -307,7 +320,7 @@ func NewClientFromInfo(info ConnectInfo) (*Client, error) {
 	if strings.HasPrefix(info.RemoteConfig.Addr, "unix:") {
 		err = connectViaUnix(c, &info.RemoteConfig)
 	} else {
-		err = connectViaHttp(c, &info.RemoteConfig, info.ClientPEMCert, info.ClientPEMKey, info.ServerPEMCert)
+		err = connectViaHttp(c, &info.RemoteConfig, info.ClientPEMCert, info.ClientPEMKey, info.ClientPEMCa, info.ServerPEMCert)
 	}
 	if err != nil {
 		return nil, err
diff --git a/doc/lxd-ssl-authentication.md b/doc/lxd-ssl-authentication.md
index f648b8e..bf50ed5 100644
--- a/doc/lxd-ssl-authentication.md
+++ b/doc/lxd-ssl-authentication.md
@@ -56,8 +56,8 @@ A CRL may also accompany the CA certificate.
 
 In that mode, any connection to a LXD daemon will be done using the
 preseeded CA certificate. If the server certificate isn't signed by the
-CA, or if it has been revoked, the connection will simply go through the
-normal authentication mechanism.
+CA, the connection will simply go through the normal authentication
+mechanism.
 
 If the server certificate is valid and signed by the CA, then the
 connection continues without prompting the user for the certificate.
@@ -67,6 +67,15 @@ it matches, the client certificate is added to the server's trust store
 and the client can now connect to the server without having to provide
 any additional credentials.
 
+Enabling PKI mode is done by replacing adding a client.ca file in the
+client's configuration directory (~/.config/lxc) and a server.ca file in
+the server's configuration directory (/var/lib/lxd). Then a client
+certificate must be issued by the CA for the client and a server
+certificate for the server. Those must then replace the existing
+pre-generated files.
+
+After this is done, restarting the server will have it run in PKI mode.
+
 # Password prompt
 To establish a new trust relationship, a password must be set on the
 server and send by the client when adding itself.
diff --git a/lxc/remote.go b/lxc/remote.go
index a01b0f6..df75e8a 100644
--- a/lxc/remote.go
+++ b/lxc/remote.go
@@ -58,7 +58,7 @@ func (c *remoteCmd) flags() {
 
 func getRemoteCertificate(address string) (*x509.Certificate, error) {
 	// Setup a permissive TLS config
-	tlsConfig, err := shared.GetTLSConfig("", "", nil)
+	tlsConfig, err := shared.GetTLSConfig("", "", "", nil)
 	if err != nil {
 		return nil, err
 	}
diff --git a/lxd/api_1.0.go b/lxd/api_1.0.go
index 19c5516..6ac93e9 100644
--- a/lxd/api_1.0.go
+++ b/lxd/api_1.0.go
@@ -45,9 +45,17 @@ var api10 = []Command{
 
 func api10Get(d *Daemon, r *http.Request) Response {
 	body := shared.Jmap{
+		/* List of API extensions in the order they were added
+		 * Is considered an API extension, any new configuration keys,
+		 * any new argument to a REST endpoint or any new REST endpoint.
+		 *
+		 * Extra authentication methods should also be included.
+		 */
 		"api_extensions": []string{
 			"syscall_filtering",
+			"auth_pki",
 		},
+
 		"api_status":  "stable",
 		"api_version": shared.APIVersion,
 	}
diff --git a/lxd/containers_post.go b/lxd/containers_post.go
index 25e37ca..c124621 100644
--- a/lxd/containers_post.go
+++ b/lxd/containers_post.go
@@ -260,7 +260,7 @@ func createFromMigration(d *Daemon, req *containerPostReq) Response {
 			}
 		}
 
-		config, err := shared.GetTLSConfig("", "", cert)
+		config, err := shared.GetTLSConfig("", "", "", cert)
 		if err != nil {
 			c.Delete()
 			return err
diff --git a/lxd/daemon.go b/lxd/daemon.go
index 49a6f7f..d8bf79d 100644
--- a/lxd/daemon.go
+++ b/lxd/daemon.go
@@ -118,7 +118,7 @@ func (d *Daemon) httpGetSync(url string, certificate string) (*lxd.Response, err
 		}
 	}
 
-	tlsConfig, err := shared.GetTLSConfig("", "", cert)
+	tlsConfig, err := shared.GetTLSConfig("", "", "", cert)
 	if err != nil {
 		return nil, err
 	}
@@ -170,7 +170,7 @@ func (d *Daemon) httpGetFile(url string, certificate string) (*http.Response, er
 		}
 	}
 
-	tlsConfig, err := shared.GetTLSConfig("", "", cert)
+	tlsConfig, err := shared.GetTLSConfig("", "", "", cert)
 	if err != nil {
 		return nil, err
 	}
@@ -212,7 +212,6 @@ func readMyCert() (string, string, error) {
 	certf := shared.VarPath("server.crt")
 	keyf := shared.VarPath("server.key")
 	shared.Log.Info("Looking for existing certificates", log.Ctx{"cert": certf, "key": keyf})
-
 	err := shared.FindOrGenCert(certf, keyf)
 
 	return certf, keyf, err
@@ -223,14 +222,17 @@ func (d *Daemon) isTrustedClient(r *http.Request) bool {
 		// Unix socket
 		return true
 	}
+
 	if r.TLS == nil {
 		return false
 	}
+
 	for i := range r.TLS.PeerCertificates {
 		if d.CheckTrustState(*r.TLS.PeerCertificates[i]) {
 			return true
 		}
 	}
+
 	return false
 }
 
@@ -247,6 +249,7 @@ func isJSONRequest(r *http.Request) bool {
 
 func (d *Daemon) isRecursionRequest(r *http.Request) bool {
 	recursionStr := r.FormValue("recursion")
+
 	recursion, err := strconv.Atoi(recursionStr)
 	if err != nil {
 		return false
@@ -798,6 +801,21 @@ func (d *Daemon) Init() error {
 				tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
 			PreferServerCipherSuites: true,
 		}
+
+		if shared.PathExists(shared.VarPath("server.ca")) {
+			ca, err := shared.ReadCert(shared.VarPath("server.ca"))
+			if err != nil {
+				return err
+			}
+
+			caPool := x509.NewCertPool()
+			caPool.AddCert(ca)
+			tlsConfig.RootCAs = caPool
+			tlsConfig.ClientCAs = caPool
+
+			shared.Log.Info("LXD is in CA mode, only CA-signed certificates will be allowed")
+		}
+
 		tlsConfig.BuildNameToCertificate()
 
 		d.tlsConfig = tlsConfig
@@ -1009,8 +1027,8 @@ func (d *Daemon) CheckTrustState(cert x509.Certificate) bool {
 			shared.Log.Debug("Found cert", log.Ctx{"k": k})
 			return true
 		}
-		shared.Log.Debug("Client cert != key", log.Ctx{"k": k})
 	}
+
 	return false
 }
 
diff --git a/lxd/images.go b/lxd/images.go
index 5013787..3410b6b 100644
--- a/lxd/images.go
+++ b/lxd/images.go
@@ -323,7 +323,7 @@ func imgPostURLInfo(d *Daemon, req imagePostReq, op *operation) error {
 	}
 
 	// Resolve the image URL
-	tlsConfig, err := shared.GetTLSConfig("", "", nil)
+	tlsConfig, err := shared.GetTLSConfig("", "", "", nil)
 	if err != nil {
 		return err
 	}
diff --git a/shared/network.go b/shared/network.go
index 08e7019..cfd2017 100644
--- a/shared/network.go
+++ b/shared/network.go
@@ -47,7 +47,10 @@ func initTLSConfig() *tls.Config {
 func finalizeTLSConfig(tlsConfig *tls.Config, tlsRemoteCert *x509.Certificate) {
 	// Trusted certificates
 	if tlsRemoteCert != nil {
-		caCertPool := x509.NewCertPool()
+		caCertPool := tlsConfig.RootCAs
+		if caCertPool == nil {
+			caCertPool = x509.NewCertPool()
+		}
 
 		// Make it a valid RootCA
 		tlsRemoteCert.IsCA = true
@@ -66,7 +69,7 @@ func finalizeTLSConfig(tlsConfig *tls.Config, tlsRemoteCert *x509.Certificate) {
 	tlsConfig.BuildNameToCertificate()
 }
 
-func GetTLSConfig(tlsClientCertFile string, tlsClientKeyFile string, tlsRemoteCert *x509.Certificate) (*tls.Config, error) {
+func GetTLSConfig(tlsClientCertFile string, tlsClientKeyFile string, tlsClientCAFile string, tlsRemoteCert *x509.Certificate) (*tls.Config, error) {
 	tlsConfig := initTLSConfig()
 
 	// Client authentication
@@ -79,11 +82,23 @@ func GetTLSConfig(tlsClientCertFile string, tlsClientKeyFile string, tlsRemoteCe
 		tlsConfig.Certificates = []tls.Certificate{cert}
 	}
 
+	if tlsClientCAFile != "" {
+		caCertificates, err := ioutil.ReadFile(tlsClientCAFile)
+		if err != nil {
+			return nil, err
+		}
+
+		caPool := x509.NewCertPool()
+		caPool.AppendCertsFromPEM(caCertificates)
+
+		tlsConfig.RootCAs = caPool
+	}
+
 	finalizeTLSConfig(tlsConfig, tlsRemoteCert)
 	return tlsConfig, nil
 }
 
-func GetTLSConfigMem(tlsClientCert string, tlsClientKey string, tlsRemoteCertPEM string) (*tls.Config, error) {
+func GetTLSConfigMem(tlsClientCert string, tlsClientKey string, tlsClientCA string, tlsRemoteCertPEM string) (*tls.Config, error) {
 	tlsConfig := initTLSConfig()
 
 	// Client authentication
@@ -106,6 +121,14 @@ func GetTLSConfigMem(tlsClientCert string, tlsClientKey string, tlsRemoteCertPEM
 			return nil, err
 		}
 	}
+
+	if tlsClientCA != "" {
+		caPool := x509.NewCertPool()
+		caPool.AppendCertsFromPEM([]byte(tlsClientCA))
+
+		tlsConfig.RootCAs = caPool
+	}
+
 	finalizeTLSConfig(tlsConfig, tlsRemoteCert)
 
 	return tlsConfig, nil
diff --git a/shared/simplestreams.go b/shared/simplestreams.go
index 7842e75..9db9994 100644
--- a/shared/simplestreams.go
+++ b/shared/simplestreams.go
@@ -222,7 +222,7 @@ type SimpleStreamsIndexStream struct {
 
 func SimpleStreamsClient(url string, proxy func(*http.Request) (*url.URL, error)) (*SimpleStreams, error) {
 	// Setup a http client
-	tlsConfig, err := GetTLSConfig("", "", nil)
+	tlsConfig, err := GetTLSConfig("", "", "", nil)
 	if err != nil {
 		return nil, err
 	}

From 22137da015111d1244915e12f74c11f5d55e2caf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Wed, 1 Jun 2016 17:17:29 -0400
Subject: [PATCH 3/3] Properly export and document recent API additions
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 doc/api_extensions.md | 40 ++++++++++++++++++++++
 doc/configuration.md  | 94 +++++++++++++++++++++++++--------------------------
 lxd/api_1.0.go        |  4 ++-
 3 files changed, 90 insertions(+), 48 deletions(-)
 create mode 100644 doc/api_extensions.md

diff --git a/doc/api_extensions.md b/doc/api_extensions.md
new file mode 100644
index 0000000..691ebdd
--- /dev/null
+++ b/doc/api_extensions.md
@@ -0,0 +1,40 @@
+# API extensions
+
+The changes below were introduced to the LXD API after the 1.0 API was finalized.
+
+They are all backward compatible and can be detected by client tools by  
+looking at the api\_extensions field in GET /1.0/.
+
+
+## storage\_zfs\_remove\_snapshots
+A storage.zfs\_remove\_snapshots daemon configuration key was introduced.
+
+It's a boolean that defaults to false and that when set to true instructs LXD  
+to remove any needed snapshot when attempting to restore another.
+
+This is needed as ZFS will only let you restore the latest snapshot.
+
+## container\_host\_shutdown\_timeout
+A boot.host\_shutdown\_timeout container configuration key was introduced.
+
+It's an integer which indicates how long LXD should wait for the container  
+to stop before killing it.
+
+Its value is only used on clean LXD daemon shutdown. It defaults to 30s.
+
+## container\_syscall\_filtering
+A number of new syscalls related container configuration keys were introduced.
+
+ * security.syscalls.blacklist\_default
+ * security.syscalls.blacklist\_compat
+ * security.syscalls.blacklist
+ * security.syscalls.whitelist
+
+See configuration.md for how to use them.
+
+## auth\_pki
+This indicates support for PKI authentication mode.
+
+In this mode, the client and server both must use certificates issued by the same PKI.
+
+See lxd-ssl-authentication.md for details.
diff --git a/doc/configuration.md b/doc/configuration.md
index 0e0de40..5b6fba4 100644
--- a/doc/configuration.md
+++ b/doc/configuration.md
@@ -17,26 +17,26 @@ currently supported:
  - images (image configuration)
  - storage (storage configuration)
 
-Key                             | Type          | Default                   | Description
-:--                             | :---          | :------                   | :----------
-core.https\_address             | string        | -                         | Address to bind for the remote API
-core.https\_allowed\_origin     | string        | -                         | Access-Control-Allow-Origin http header value
-core.https\_allowed\_methods    | string        | -                         | Access-Control-Allow-Methods http header value
-core.https\_allowed\_headers    | string        | -                         | Access-Control-Allow-Headers http header value
-core.proxy\_https               | string        | -                         | https proxy to use, if any (falls back to HTTPS\_PROXY environment variable)
-core.proxy\_http                | string        | -                         | http proxy to use, if any (falls back to HTTP\_PROXY environment variable)
-core.proxy\_ignore\_hosts       | string        | -                         | hosts which don't need the proxy for use (similar format to NO\_PROXY, e.g. 1.2.3.4,1.2.3.5, falls back to NO\_PROXY environment variable)
-core.trust\_password            | string        | -                         | Password to be provided by clients to setup a trust
-storage.lvm\_vg\_name           | string        | -                         | LVM Volume Group name to be used for container and image storage. A default Thin Pool is created using 100% of the free space in the Volume Group, unless `storage.lvm_thinpool_name` is set.
-storage.lvm\_thinpool\_name     | string        | "LXDPool"                 | LVM Thin Pool to use within the Volume Group specified in `storage.lvm_vg_name`, if the default pool parameters are undesirable.
-storage.lvm\_fstype             | string        | ext4                      | Format LV with filesystem, for now it's value can be only ext4 (default) or xfs.
-storage.lvm\_volume\_size       | string        | 10GiB                     | Size of the logical volume
-storage.zfs\_pool\_name         | string        | -                         | ZFS pool name
-storage.zfs\_remove\_snapshots  | boolean       | false                     | Automatically remove any needed snapshot when attempting a container restore
-images.compression\_algorithm   | string        | gzip                      | Compression algorithm to use for new images (bzip2, gzip, lzma, xz or none)
-images.remote\_cache\_expiry    | integer       | 10                        | Number of days after which an unused cached remote image will be flushed
-images.auto\_update\_interval   | integer       | 6                         | Interval in hours at which to look for update to cached images (0 disables it)
-images.auto\_update\_cached     | boolean       | true                      | Whether to automatically update any image that LXD caches
+Key                             | Type      | Default   | API extension                     | Description
+:--                             | :---      | :------   | :------------                     | :----------
+core.https\_address             | string    | -         | -                                 | Address to bind for the remote API
+core.https\_allowed\_origin     | string    | -         | -                                 | Access-Control-Allow-Origin http header value
+core.https\_allowed\_methods    | string    | -         | -                                 | Access-Control-Allow-Methods http header value
+core.https\_allowed\_headers    | string    | -         | -                                 | Access-Control-Allow-Headers http header value
+core.proxy\_https               | string    | -         | -                                 | https proxy to use, if any (falls back to HTTPS\_PROXY environment variable)
+core.proxy\_http                | string    | -         | -                                 | http proxy to use, if any (falls back to HTTP\_PROXY environment variable)
+core.proxy\_ignore\_hosts       | string    | -         | -                                 | hosts which don't need the proxy for use (similar format to NO\_PROXY, e.g. 1.2.3.4,1.2.3.5, falls back to NO\_PROXY environment variable)
+core.trust\_password            | string    | -         | -                                 | Password to be provided by clients to setup a trust
+storage.lvm\_vg\_name           | string    | -         | -                                 | LVM Volume Group name to be used for container and image storage. A default Thin Pool is created using 100% of the free space in the Volume Group, unless `storage.lvm_thinpool_name` is set.
+storage.lvm\_thinpool\_name     | string    | "LXDPool" | -                                 | LVM Thin Pool to use within the Volume Group specified in `storage.lvm_vg_name`, if the default pool parameters are undesirable.
+storage.lvm\_fstype             | string    | ext4      | -                                 | Format LV with filesystem, for now it's value can be only ext4 (default) or xfs.
+storage.lvm\_volume\_size       | string    | 10GiB     | -                                 | Size of the logical volume
+storage.zfs\_pool\_name         | string    | -         | -                                 | ZFS pool name
+storage.zfs\_remove\_snapshots  | boolean   | false     | storage\_zfs\_remove\_snapshots   | Automatically remove any needed snapshot when attempting a container restore
+images.compression\_algorithm   | string    | gzip      | -                                 | Compression algorithm to use for new images (bzip2, gzip, lzma, xz or none)
+images.remote\_cache\_expiry    | integer   | 10        | -                                 | Number of days after which an unused cached remote image will be flushed
+images.auto\_update\_interval   | integer   | 6         | -                                 | Interval in hours at which to look for update to cached images (0 disables it)
+images.auto\_update\_cached     | boolean   | true      | -                                 | Whether to automatically update any image that LXD caches
 
 Those keys can be set using the lxc tool with:
 
@@ -64,33 +64,33 @@ currently supported:
 
 The currently supported keys are:
 
-Key                                  | Type      | Default       | Live update   | Description
-:--                                  | :---      | :------       | :----------   | :----------
-boot.autostart                       | boolean   | false         | n/a           | Always start the container when LXD starts
-boot.autostart.delay                 | integer   | 0             | n/a           | Number of seconds to wait after the container started before starting the next one
-boot.autostart.priority              | integer   | 0             | n/a           | What order to start the containers in (starting with highest)
-boot.host_shutdown_timeout           | integer   | 30            | yes           | Seconds to wait for container to shutdown before it is force stopped
-environment.\*                       | string    | -             | yes (exec)    | key/value environment variables to export to the container and set on exec
-limits.cpu                           | string    | - (all)       | yes           | Number or range of CPUs to expose to the container
-limits.cpu.allowance                 | string    | 100%          | yes           | How much of the CPU can be used. Can be a percentage (e.g. 50%) for a soft limit or hard a chunk of time (25ms/100ms)
-limits.cpu.priority                  | integer   | 10 (maximum)  | yes           | CPU scheduling priority compared to other containers sharing the same CPUs (overcommit)
-limits.disk.priority                 | integer   | 5 (medium)    | yes           | When under load, how much priority to give to the container's I/O requests
-limits.memory                        | string    | - (all)       | yes           | Percentage of the host's memory or fixed value in bytes (supports kB, MB, GB, TB, PB and EB suffixes)
-limits.memory.enforce                | string    | hard          | yes           | If hard, container can't exceed its memory limit. If soft, the container can exceed its memory limit when extra host memory is available.
-limits.memory.swap                   | boolean   | true          | yes           | Whether to allow some of the container's memory to be swapped out to disk
-limits.memory.swap.priority          | integer   | 10 (maximum)  | yes           | The higher this is set, the least likely the container is to be swapped to disk
-limits.network.priority              | integer   | 0 (minimum)   | yes           | When under load, how much priority to give to the container's network requests
-limits.processes                     | integer   | - (max)       | yes           | Maximum number of processes that can run in the container
-linux.kernel\_modules                | string    | -             | yes           | Comma separated list of kernel modules to load before starting the container
-raw.apparmor                         | blob      | -             | yes           | Apparmor profile entries to be appended to the generated profile
-raw.lxc                              | blob      | -             | no            | Raw LXC configuration to be appended to the generated one
-security.nesting                     | boolean   | false         | yes           | Support running lxd (nested) inside the container
-security.privileged                  | boolean   | false         | no            | Runs the container in privileged mode
-security.syscalls.blacklist\_default | boolean   | true          | no            | Enables the default syscall blacklist
-security.syscalls.blacklist\_compat  | boolean   | false         | no            | On x86\_64 this enables blocking of compat\_\* syscalls, it is a no-op on other arches
-security.syscalls.blacklist          | string    | -             | no            | A '\n' separated list of syscalls to blacklist
-seucrity.syscalls.whitelist          | string    | -             | no            | A '\n' separated list of syscalls to whitelist (mutually exclusive with security.syscalls.blacklist\*)
-user.\*                              | string    | -             | n/a           | Free form user key/value storage (can be used in search)
+Key                                  | Type      | Default       | Live update   | API extension                        | Description
+:--                                  | :---      | :------       | :----------   | :------------                        | :----------
+boot.autostart                       | boolean   | false         | n/a           | -                                    | Always start the container when LXD starts
+boot.autostart.delay                 | integer   | 0             | n/a           | -                                    | Number of seconds to wait after the container started before starting the next one
+boot.autostart.priority              | integer   | 0             | n/a           | -                                    | What order to start the containers in (starting with highest)
+boot.host\_shutdown\_timeout         | integer   | 30            | yes           | container\_host\_shutdown\_timeout   | Seconds to wait for container to shutdown before it is force stopped
+environment.\*                       | string    | -             | yes (exec)    | -                                    | key/value environment variables to export to the container and set on exec
+limits.cpu                           | string    | - (all)       | yes           | -                                    | Number or range of CPUs to expose to the container
+limits.cpu.allowance                 | string    | 100%          | yes           | -                                    | How much of the CPU can be used. Can be a percentage (e.g. 50%) for a soft limit or hard a chunk of time (25ms/100ms)
+limits.cpu.priority                  | integer   | 10 (maximum)  | yes           | -                                    | CPU scheduling priority compared to other containers sharing the same CPUs (overcommit)
+limits.disk.priority                 | integer   | 5 (medium)    | yes           | -                                    | When under load, how much priority to give to the container's I/O requests
+limits.memory                        | string    | - (all)       | yes           | -                                    | Percentage of the host's memory or fixed value in bytes (supports kB, MB, GB, TB, PB and EB suffixes)
+limits.memory.enforce                | string    | hard          | yes           | -                                    | If hard, container can't exceed its memory limit. If soft, the container can exceed its memory limit when extra host memory is available.
+limits.memory.swap                   | boolean   | true          | yes           | -                                    | Whether to allow some of the container's memory to be swapped out to disk
+limits.memory.swap.priority          | integer   | 10 (maximum)  | yes           | -                                    | The higher this is set, the least likely the container is to be swapped to disk
+limits.network.priority              | integer   | 0 (minimum)   | yes           | -                                    | When under load, how much priority to give to the container's network requests
+limits.processes                     | integer   | - (max)       | yes           | -                                    | Maximum number of processes that can run in the container
+linux.kernel\_modules                | string    | -             | yes           | -                                    | Comma separated list of kernel modules to load before starting the container
+raw.apparmor                         | blob      | -             | yes           | -                                    | Apparmor profile entries to be appended to the generated profile
+raw.lxc                              | blob      | -             | no            | -                                    | Raw LXC configuration to be appended to the generated one
+security.nesting                     | boolean   | false         | yes           | -                                    | Support running lxd (nested) inside the container
+security.privileged                  | boolean   | false         | no            | -                                    | Runs the container in privileged mode
+security.syscalls.blacklist\_default | boolean   | true          | no            | container\_syscall\_filtering        | Enables the default syscall blacklist
+security.syscalls.blacklist\_compat  | boolean   | false         | no            | container\_syscall\_filtering        | On x86\_64 this enables blocking of compat\_\* syscalls, it is a no-op on other arches
+security.syscalls.blacklist          | string    | -             | no            | container\_syscall\_filtering        | A '\n' separated list of syscalls to blacklist
+security.syscalls.whitelist          | string    | -             | no            | container\_syscall\_filtering        | A '\n' separated list of syscalls to whitelist (mutually exclusive with security.syscalls.blacklist\*)
+user.\*                              | string    | -             | n/a           | -                                    |Free form user key/value storage (can be used in search)
 
 The following volatile keys are currently internally used by LXD:
 
diff --git a/lxd/api_1.0.go b/lxd/api_1.0.go
index 6ac93e9..ac854c8 100644
--- a/lxd/api_1.0.go
+++ b/lxd/api_1.0.go
@@ -52,7 +52,9 @@ func api10Get(d *Daemon, r *http.Request) Response {
 		 * Extra authentication methods should also be included.
 		 */
 		"api_extensions": []string{
-			"syscall_filtering",
+			"storage_zfs_remove_snapshots",
+			"container_host_shutdown_timeout",
+			"container_syscall_filtering",
 			"auth_pki",
 		},
 


More information about the lxc-devel mailing list