During startup memcached binds to ephemeral ports on the
loopback interface and writes the port(s) to the file specified in
portnumber_file
in the provided configuration
(it is the responsibility of the process starting memcached to ensure that
the directory is writable for memcached).
Once the file exists memcached is "up'n'running" and listening to the ports listed in the file and ready for clients to connect and perform additional configuration.
Note that after a restart the configuration is gone and memcached
will try to bind to new ephemeral ports and store them in the
portnumber_file
.
A controlling process could implement the logic by doing something like:
config["portnumber_file"] = "/opt/couchbase/var/lib/couchbase/run/memcached.ports.0001";
write_file("/opt/couchbase/var/lib/couchbase/etc/memcached.json", config);
auto handle = startProcess("/opt/couchbase/bin/memcached", "-C", "/opt/couchbase/var/lib/couchbase/etc/memcached.json");
while (handle->isRunning() && !isFile(config["portnumber_file"])) {
backoff();
}
ports = readJsonFile(config["portnumber_file"])["ports"];
// memcached is up'n'running, set up TLS
nlohmann::json tls_properties = {
{"private key", "/opt/couchbase/var/lib/couchbase/etc/private.pem"},
{"certificate chain", "/opt/couchbase/var/lib/couchbase/etc/certificate.cert"},
{"CA file", "/opt/couchbase/var/lib/couchbase/etc/CAfile.pem"},
{"password", cb::base64::encode("This is the passphrase")},
{"minimum version", "TLS 1.2"},
{"cipher list",
{{"TLS 1.2", "HIGH"},
{"TLS 1.3",
"TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_"
"AES_"
"128_GCM_SHA256:TLS_AES_128_CCM_8_SHA256:TLS_AES_128_CCM_"
"SHA256"}}},
{"cipher order", true},
{"client cert auth", "disabled"}};
BinprotGenericCommand cmd(cb::mcbp::ClientOpcode::Ifconfig);
cmd.setKey("tls");
cmd.setValue(tls_properties.dump());
auto rsp = conn.execute(cmd);
if (!rsp.isSuccess()) {
// handle error!
}
nlohmann::json descr = {{"host", "*"},
{"port", 11210},
{"family", "inet"},
{"system", false},
{"type", "mcbp"},
{"tls", true};
BinprotGenericCommand cmd(cb::mcbp::ClientOpcode::Ifconfig);
cmd.setKey("define");
cmd.setValue(descr.dump());
auto rsp = conn.execute(cmd);
if (!rsp.isSuccess()) {
// handle error
}
ports.addInterface(rsp.getValue()):
// people may now connect port 11210 using TLS
The ifconfig command takes a command name in the key field, and the value field contains a command-specific payload.
The connection must hold the NodeManagement
privilege to run
the command.
Key - Define
The body contains a JSON document describing the interface to create:
{
"host" : "hostname"
"port" : port,
"family" : "inet[6]",
"tls" : true,
"system" : false,
"tag" : "optional free form name for the interface",
"type": "interface type (see below)"
}
-
host
may be set to*
to bind to all interfaces, a textual name to look up or an ip address. (defaults to "localhost"). -
port
may be0
(default) to let the kernel pick an ephemeral port -
family
may beinet
for IPv4 andinet6
for IPv6 (mandatory). -
tls
is a boolean value indicating if the port is set up to use OpenSSL or not (if set to true the TLS configuration must be specified for the port to "work" (otherwise the client will be disconnected). No attempts will be made to make sure that this interface is working when it is defined, as it is possible to reconfigure the system so that the interface will no longer work at a later time (for instance by providing obsolete certificates etc)). -
system
indicates if connections over this interface should be counted for from the the system connection pool or the user connection pool. -
type
may be one of the following:mcbp The network interface should be used by normal client-server traffic using the memcached binary protocol
prometheus The network interface should be used by prometheus to collect statistics. host, ssl and system must not be set.
Upon success (at least one port created) the returned payload is a JSON document with all of the properties for the newly created ports and an array containing all errors returned while trying to create the ports (for instance if one port failed to bind)
{
"errors": [
"error message 1",
"error message 2"
],
"ports": [
{
"family": "inet",
"host": "0.0.0.0",
"port": 38649,
"system": false,
"tag": "yo",
"type": "mcbp",
"uuid": "ec3db10c-762c-4205-c4ce-b02c014fb44c"
}
]
}
If the status of the operation can't be represented with the
standard error codes (einval
, eaccess
etc) the returned
payload contains a JSON document with the following layout:
{
"error": {
"context" : "Failed to create any ports",
"errors": [
"message 1",
"message 2"
]
}
}
Key - Delete
The body contains a the uuid for the interface to delete.
If the status of the operation can't be represented with the
standard error codes (success
, enoent
, einval
, eaccess
etc) the returned payload contains more information just like
create.
Key - List
Upon success the following JSON payload is returned:
[
{
"family": "inet",
"host": "0.0.0.0",
"port": 34961,
"system": false,
"tag": "plain",
"type": "mcbp",
"uuid": "f6f6a824-d702-4208-2e7e-106f8b6661e1"
},
{
"family": "inet6",
"host": "::",
"port": 39445,
"system": false,
"tag": "plain",
"type": "mcbp",
"uuid": "a0f99fa0-df5a-4e64-e86e-59e242277758"
},
{
"family": "inet",
"host": "0.0.0.0",
"port": 36437,
"system": true,
"tag": "ssl",
"tls": true,
"type": "mcbp",
"uuid": "5d64edf3-6bf0-4fe5-583e-68ceff8e4d04"
},
{
"family": "inet6",
"host": "::",
"port": 40855,
"system": true,
"tag": "ssl",
"tls": true,
"type": "mcbp",
"uuid": "5b6c27db-a214-4db6-4a3e-44bbcfd36d68"
},
{
"family": "inet",
"host": "127.0.0.1",
"port": 37183,
"type": "prometheus",
"uuid": "b1ba0893-930c-450a-a1a0-45ce88e25611"
}
]
If the error can't be represented with the standard error codes
(enoent
, einval
, eaccess
etc) the returned payload
contains more information just like create.
Key - TLS
The body contains the new TLS configuration to use described as a JSON object with the following layout:
{
"private key": "/path/to/file/containing/private/key",
"certificate chain": "/path/to/file/containing/certificate/chain",
"CA file", "/opt/couchbase/var/lib/couchbase/etc/CAfile.pem",
"password" : "base64-encoded version of the password to decrypt private key",
"minimum version", "TLS 1.2",
"cipher list" : {
"TLS 1.2" : "ciphers for TLS <= 1.2",
"TLS 1.3" : "ciphers for TLS 1.3"
},
"cipher order" : true,
"client cert auth" : "mandatory"
}
On success the current TLS configuration is returned as JSON.
private key
contains the path to a file containing the private key. Memcached will not keep the file open after the content was read (no later than a response was sent for the request)certificate chain
contains the path to a file containing the certificate chain. Like theprivate key
the file will not be held open.CA file
contains the path to a file containing all the certificate authorities.password
contains the password to decrypt the password. To make it easier to transfer all kinds of characters the string should be base64 encoded.minimum version
specifies the minimum TLS version to be used, and may be one of the following values: "TLS 1.2" and "TLS 1.3". see https://en.wikipedia.org/wiki/Comparison_of_TLS_implementations for more information.cipher list
is an object containing two keys:TLS 1.2
contains the list of ciphers to use for TLS 1.2TLS 1.3
contains the cipher suites to use for TLS 1.3
cipher order
specifies if the server should choose the cipher to use based on its preferences (order they are specified).client cert auth
specifies the authentication mode and may be one of the following values:disabled
- The client must authenticate using SASLenabled
- Try to authenticate the user from the client certificate, but let the user authenticate via SASL if we fail to lookup a user.mandatory
- Authenticate the user based upon the content of the certificate, and disconnect the user if we fail to do so. SASL would NOT be possible for these connections.
Note that the mapping rules for client certificate authentication remains
with the rest of the settings in memcached.json
.