Remove automatic creation of TLS certificate

The automatic creation of a self-signed certificate while nice presents
several problems.  To make connections not reject the self-signed
certificate the validation of TLS certificates are wholesale disabled,
decreasing the security even when properly set up and trusted
certificates are used.

To make the created self-signed certificate pass validation it is
necessary for it to list the host names it's valid for and to copy it to
each machine that intends to connect to the server.  These two steps
complicate automating the process in a reliable way and will likely lead
to confused users seeking to disable TLS certificate validation as the
easy way out to problems.

For these reasons, remove the automating creation of a broke self-signed
certificate, fix validation of certificates and document how to set up
TLS properly.  This makes HTTPS recommended when accessing over the
internet, but still something which must be explicitly configured.
This commit is contained in:
Hornwitser committed 2021-01-04 08:22:05 +01:00
1 parent a094a06cd1
commit 3592ff3269
16 files changed
+343 -179

No files matched your search

+2 -2
View File
@@ -54,11 +54,10 @@ Version 2.0.0
- Added metric mapping of slave and instance ids to their names, allowing
them to be displayed by name in queries that join with the mapping.
- Added option to configure timeout for exported Prometheus metrics.
- Added option to set address to bind HTTP(S) port to.
### Changes
- Fixed sslCert and sslPrivKey entries being ignored in the config.
- Changed ssl key creation to be done at startup instead of on npm install.
- Added error handling during master startup.
- Factorio game and rcon port now defaults to a random port above 49151.
- Removed unimplemented mods update command.
@@ -180,6 +179,7 @@ Version 2.0.0
- Removed usage of socket.io entirely in favor of a plain WebSocket connection.
- Renamed clusterioMod plugin to subspace_storage.
- Master no longer creates secret-api-token.txt.
- Removed automatic creation of self-signed TLS certificate.
Version 1.2.4
+8 -45
View File
@@ -206,21 +206,21 @@ with either . or .. (which will then be resolved to an absolute path).
## Configure Master Server
By default the master server will create a self signed TLS certificate
and listen on HTTPS on port 8443. You can change the port used with the
command
By default the master server will listen for HTTP on port 8080. You can
change the port used with the command
npx clusteriomaster config set master.https_port 1234
npx clusteriomaster config set master.http_port 1234
If you plan to make your cluster available externally set the address
that it will be accessible under with, for example
npx clusteriomaster config set master.external_address https://192.0.2.4:8443/
npx clusteriomaster config set master.external_address http://203.0.113.4:1234/
Change the url to reflect the IP, protocol, and port the master server
is accessible under, dns names are also supported. If proxyed under a
sub-path include the sub path as well and make sure the URL ends with a
slash.
is accessible under, dns names are also supported. If you're planning
on making the master server accessible on the internet it's recommended
to set up TLS, see the [Setting Up TLS](/docs/setting-up-tls.md)
document for more details.
You can list the config of the master server with the `npx
clusteriomaster config list` command. See the [readme for
@@ -228,43 +228,6 @@ clusteriomaster config list` command. See the [readme for
information.
### Hosting Behind Proxy
If you want to host the master server behind a reverse proxy the
recommended setup is to disable HTTPS and host it on a high port
over HTTP to which you point your proxy to. For example to configure
port 8080 as the HTTP port for the master server.
npx clusteriomaster config set master.https_port # unsets https_port
npx clusteriomaster config set master.http_port 8080
The proxy can then forward requests to a sub-path like `/cluster/` to
`http://localhost:8080/`.
Additianlly WebSocket connections to api/socket relative to the sub-path
the interface is hosted under also needs to be forwarded. See below for
the specifics of setting this up on Apache.
#### Apache Config
To proxy with Apache make sure that proxy_module, proxy_http_module and
proxy_wstunnel_module is loaded in the config, then add the following
directives to wherever is the approriate place for your flavour of
Apache config organization.
```apache
<Location /cluster/>
ProxyPass "http://localhost:8080/"
</location>
<Location /cluster/api/socket>
ProxyPass "ws://localhost:8080/api/socket"
</Location>
```
Pay attention to the use of trailing slashes, they are important.
### Setting up an admin account
Before you can manage the cluster you need to bootstrap an admin account
+63 -17
View File
@@ -19,7 +19,7 @@ Port to host HTTP server on. If set to null no HTTP server will be
exposed. At least one of this and master.https_port needs to be set to
a port.
Defaults to null.
Defaults to 8080.
### master.https_port
@@ -29,7 +29,10 @@ master.tls_private_key as the certificate and private key for the HTTPS
server. If set to null no HTTPS server will be exposed. At least one
of this and master.http_port needs to be set to a port.
Defaults to 8443.
See the [Setting up TLS](/docs/setting-up-tls.md) document for a guide
to setting up HTTPS with Clusterio.
Defaults to null.
### master.bind_address
@@ -54,29 +57,20 @@ Defaults to null meaning assume localhost.
### master.tls_certificate
TLS certificate to use for the HTTPS server when master.https_port is
configured. If neither this nor the configured master.tls_private_key
exists a self signed certificate is automatically created.
Path to TLS certificate to use for the HTTPS server when
master.https_port is configured.
Defaults to "database/certificates/cert.crt".
### master.tls_private_key
TLS private key to use for the HTTPS server when master.https_port is
configured. If neither this nor the configured master.tls_certificate
exists a self signed certificate is automatically created.
Path to TLS private key to use for the HTTPS server when
master.https_port is configured.
Defaults to "database/certificates/cert.key".
### master.tls_bits
Number of bits to use when creating a self signed certificate.
Defaults to 2048.
### master.auth_secret
Base64 encoded authentication secret used to verify tokens issued to
@@ -178,7 +172,7 @@ Defaults to "instances".
URL to connect to the master server to.
Defaults to "https://localhost:8443/".
Defaults to "http://localhost:8080/".
### slave.master_token
@@ -191,6 +185,17 @@ create a new slave config with the correct url and token in it.
Defaults to "enter token here".
### slave.tls_ca
Path to certificate in PEM format to use for validating a TLS connection
to the master server. If you have a self signed certificate on the
master server you will need to copy the certificate to your slaves and
set it as the certificate authority with this option.
Defaults to null meaning use Node.js's default set of trusted
certificate authorities.
### slave.public_address
External address instances hosted on this slave can be accessed on.
@@ -211,7 +216,7 @@ Defaults to 5.
Instance Configuration
======================
----------------------
### instance.name
@@ -419,3 +424,44 @@ need to be enabled on the master server in order for them to be loaded
on instances.
Defaults to true
Control Configuration
---------------------
### control.master_url
URL to connect to the master server to.
Defaults to null meaning complain about it not being set and exit.
### control.master_token
Access token used for authenticating with the master server. You can
generate an access token with `clusteriomaster bootstrap
generate-user-token <username>`, or use the `clusteriomaster bootstrap
create-ctl-config <username>` to create a new ctl config with the
correct url and token in it.
Defaults to null meaning complain about it not being set and exit.
### control.tls_ca
Path to certificate in PEM format to use for validating a TLS connection
to the master server. If you have a self signed certificate on the
master server you will need to copy the certificate to the computer you
run clusterctl from and set it as the certificate authority with this
option.
Defaults to null meaning use Node.js's default set of trusted
certificate authorities.
### control.reconnect_delay
Duration in seconds to wait before attempting to reconnect with the
master server after the connection is dropped.
Defaults to 2.
+112
View File
@@ -0,0 +1,112 @@
Setting up TLS
==============
By default Clusterio will listen for connections over HTTP which is fine
for local networks but over the Internet it should idealy be over HTTPS
as there are some credentials that could be exposed to eavesdroppers.
The recommended setup is to have an ordinary HTTPS server software like
Apache or Nginx to act as a reverse proxy in front of the Clusterio
master server. The reverse proxy would then be set up with a TLS
certificate from a Certificate Authoritiy like [Let's
Encrypt](https://letsencrypt.org). Alternatively you can have Clusterio
listen for connections over HTTPS directly by providing it with a TLS
certificate and private key.
Note that a TLS certificate signed by a recognized Certificate Authority
in general requires that you own a domain. See the last section for how
to create and use a self-signed certificate for an IP address if you
don't have a domain.
Using a reverse proxy
---------------------
Configure the proxy to forward requests over HTTP to the port the master
server is listening to so that for example a request to
`https://example.com/instances/` is forwarded to
`http://localhost:8080/instances/`. It is possible to host the
interface under a sub-path, in that case a request under the sub-path
should be mapped to the master server with the sub-path stripped out.
For example `https://example.com/sub/path/instances/` would be mapped to
`http://localhost:8080/instances`.
Additianlly WebSocket connections to `/api/socket` also needs to be
forwarded. Typically this requires explicit configuration and support
for forwarding WebSocket connections. If the interface hosted under a
sub-path the `/api/socket` address is relative to the sub-path and the
sub-path also needs to be stripped out when forwarded.
You can also optionally set the master server to listen only on the
loopback interface to prevent it being directly connected to from the
outside.
npx clusteriomaster config set master.bind_address 127.0.0.1
### Apache Config
To proxy with Apache make sure that `proxy_module`, `proxy_http_module`
and `proxy_wstunnel_module` is loaded in the config, then add the
following directives to wherever is the approriate place for your
flavour of Apache config organization.
```apache
<Location /sub/path/>
ProxyPass "http://localhost:8080/"
</location>
<Location /sub/path/api/socket>
ProxyPass "ws://localhost:8080/api/socket"
</Location>
```
Replace `/sub/path/` with the location on the proxy you want to host the
Clusterio interface under. If the whole domain is to be dedicated to
the Clusterio interface then `/sub/path/` should be just `/`. Pay
attention to the use of trailing slashes, as they are important.
Hosting HTTPS directly from Node.js
-----------------------------------
Listening on HTTPS is supported by the Clusterio master server via the
`master.https_port` option provided paths to a certificate file and a
private key file is configured for the `master.tls_certificate` and
`master.tls_private_key` options. Both of these are expected to be
unencrypted PEM files.
Creating and using a self-signed certificate
--------------------------------------------
Create a self-signed certificate with OpenSSL by running
openssl req -x509 -newkey rsa:2048 -nodes -keyout key.pem -out cert.pem -days 3650 -subj /CN=localhost -addext "subjectAltName=IP:<ip>"
substituting `<ip>` with the IP address the server will be accessed
under, for example `IP:203.0.113.4`. Multiple addresses can be given by
supplying a comma sepparated list of `IP:address` pairs and DNS names
can also be specified using the `DNS:example.com` format. You need to
supply every name you want to connect to the server under the
subjectAltName field, for example to connect to the HTTPS port locally
via an address like `https://localhost:4443/` you need to add
`DNS:localhost`.
This creates a private key file named `key.pem` and a public certificate
file named `cert.pem` and these are used for the
`master.tls_certificate` and `master.tls_private_key` config options
respectively on the master server:
npx clusteriomaster config set master.tls_certificate cert.pem
npx clusteriomaster config set master.tls_private_key key.pem
Additionally you will need copy the `cert.pem` file to all of the
computers you want to set up as slaves and configure it as the
`slave.tls_ca` option:
npx clusterioslave config set slave.tls_ca cert.pem
You will also need to copy the `cert.pem` file to all of the computers
you want to remotely manage the cluster via clusterctl and configure it
as `control.tls_ca` option:
npx clusterioctl control-config set control.tls_ca cert.pem
+9 -2
View File
@@ -549,8 +549,8 @@ debugCommands.add(new libCommand.Command({
* @private
*/
class ControlConnector extends libLink.WebSocketClientConnector {
constructor(url, reconnectDelay, token) {
super(url, reconnectDelay);
constructor(url, reconnectDelay, tlsCa, token) {
super(url, reconnectDelay, tlsCa);
this._token = token;
}
@@ -765,9 +765,16 @@ async function startControl() {
return;
}
let tlsCa = null;
let tlsCaPath = controlConfig.get("control.tls_ca");
if (tlsCaPath) {
tlsCa = await fs.readFile(tlsCaPath);
}
let controlConnector = new ControlConnector(
controlConfig.get("control.master_url"),
controlConfig.get("control.reconnect_delay"),
tlsCa,
controlConfig.get("control.master_token")
);
let control = new Control(controlConnector, controlPlugins);
+14 -11
View File
@@ -24,6 +24,7 @@ MasterGroup.define({
description: "Port to listen for HTTP connections on, set to null to not listen for HTTP connections.",
type: "number",
optional: true,
initial_value: 8080,
});
MasterGroup.define({
name: "https_port",
@@ -31,7 +32,6 @@ MasterGroup.define({
description: "Port to listen for HTTPS connection on, set to null to not listen for HTTPS connections.",
type: "number",
optional: true,
initial_value: 8443,
});
MasterGroup.define({
name: "bind_address",
@@ -53,7 +53,6 @@ MasterGroup.define({
description: "Path to the certificate to use for HTTPS.",
type: "string",
optional: true,
initial_value: "database/certificates/cert.crt",
});
MasterGroup.define({
name: "tls_private_key",
@@ -61,14 +60,6 @@ MasterGroup.define({
description: "Path to the private key to use for HTTPS.",
type: "string",
optional: true,
initial_value: "database/certificates/cert.key",
});
MasterGroup.define({
name: "tls_bits",
title: "TLS Bits",
description: "Number of bits to use for auto generated TLS certificate.",
type: "number",
initial_value: 2048,
});
MasterGroup.define({
name: "auth_secret",
@@ -155,7 +146,7 @@ SlaveGroup.define({
name: "master_url",
description: "URL to connect to the master server at",
type: "string",
initial_value: "https://localhost:8443/",
initial_value: "http://localhost:8080/",
});
SlaveGroup.define({
name: "master_token",
@@ -163,6 +154,12 @@ SlaveGroup.define({
type: "string",
initial_value: "enter token here",
});
SlaveGroup.define({
name: "tls_ca",
description: "Path to Certificate Authority to validate TLS connection to master against.",
type: "string",
optional: true,
});
SlaveGroup.define({
name: "public_address",
description: "Public facing address players should connect to in order to join instances on this slave",
@@ -337,6 +334,12 @@ ControlGroup.define({
type: "string",
optional: true,
});
ControlGroup.define({
name: "tls_ca",
description: "Path to Certificate Authority to validate TLS connection to master against.",
type: "string",
optional: true,
});
ControlGroup.define({
name: "reconnect_delay",
title: "Reconnect Delay",
+18 -7
View File
@@ -144,10 +144,11 @@ class WebSocketBaseConnector extends events.EventEmitter {
* @memberof module:lib/link
*/
class WebSocketClientConnector extends WebSocketBaseConnector {
constructor(url, reconnectDelay) {
constructor(url, reconnectDelay, tlsCa = null) {
super();
this._url = url;
this._tlsCa = tlsCa;
// The following states are used in the client connector
// new: Not connected
@@ -243,11 +244,9 @@ class WebSocketClientConnector extends WebSocketBaseConnector {
this._socket = new WebSocket(url);
} else {
this._socket = new WebSocket(url, {
// For now we do not verify TLS certificates since the default setup is
// to create a self-signed certificate.
rejectUnauthorized: false,
});
let options = {};
if (this._tlsCa) { options.ca = this._tlsCa; }
this._socket = new WebSocket(url, options);
}
this._attachSocketHandlers();
@@ -317,7 +316,19 @@ class WebSocketClientConnector extends WebSocketBaseConnector {
this._socket.onerror = event => {
// It's assumed that close is always called by ws
logger.error(`SOCKET | Error: ${event.message || "unknown error"}`);
let code = !event.error ? "" : `, code: ${event.error.code}`;
logger.error(`SOCKET | Error: ${event.message || "unknown error"}${code}`);
if (event.error) {
// Abort connection if certificate validation failed
if ([
"CERT_HAS_EXPIRED",
"DEPTH_ZERO_SELF_SIGNED_CERT",
"ERR_TLS_CERT_ALTNAME_INVALID",
].includes(event.error.code)) {
this.emit("error", new libErrors.AuthenticationFailed(event.error.message));
this._state = "closing";
}
}
};
this._socket.onopen = () => {
+5 -9
View File
@@ -48,7 +48,6 @@ let db = {
};
// homebrew modules
const generateSslCert = require("./src/generate_ssl_cert");
const HttpCloser = require("./src/HttpCloser");
const routes = require("./src/routes");
const libDatabase = require("@clusterio/lib/database");
@@ -1955,14 +1954,11 @@ async function startServer() {
let tls_cert = masterConfig.get("master.tls_certificate");
let tls_key = masterConfig.get("master.tls_private_key");
// Create a self signed certificate if the certificate files doesn't exist
if (httpsPort && !await fs.exists(tls_cert) && !await fs.exists(tls_key)) {
await generateSslCert({
bits: masterConfig.get("master.tls_bits"),
sslCertPath: tls_cert,
sslPrivKeyPath: tls_key,
doLogging: true,
});
if (httpsPort && (!tls_cert || !tls_key)) {
throw new libErrors.StartupError(
"tls_certificate and tls_private_key must be configure in order to use https_port"
);
}
// Add routes for the web interface
-43
View File
@@ -1,43 +0,0 @@
"use strict";
const forge = require("node-forge");
const fs = require("fs-extra");
const util = require("util");
const { logger } = require("@clusterio/lib/logging");
const hrtime = process.hrtime.bigint;
module.exports = async function({
bits = 2048,
sslCertPath,
sslPrivKeyPath,
} = {}){
logger.info(`Generating SSL certificate with ${bits} bits at ${sslCertPath}`);
let startNs = hrtime();
let keypair = await util.promisify(forge.pki.rsa.generateKeyPair)({ bits: bits, e: 0x10001 });
logger.info(`Generated ${bits}bit keypair in: ${Number(hrtime()-startNs) / 1e6} ms`);
startNs = hrtime();
let cert = forge.pki.createCertificate();
cert.publicKey = keypair.publicKey;
cert.serialNumber = "01";
cert.validity.notBefore = new Date();
cert.validity.notAfter = new Date(Date.now()+(1000*60*60*24*365)); // valid for one year
// XXX This should probably be limited to the actual hostname
let attrs = [{ name: "commonName", value: "*" }];
cert.setSubject(attrs);
cert.setIssuer(attrs);
// self-sign certificate
cert.sign(keypair.privateKey);
// Write certificate and private key to pem files
await fs.outputFile(sslPrivKeyPath, forge.pki.privateKeyToPem(keypair.privateKey));
await fs.outputFile(sslCertPath, forge.pki.certificateToPem(cert));
logger.info(`Generated certificate in: ${Number(hrtime()-startNs) / 1e6} ms`);
};
+13 -3
View File
@@ -890,8 +890,12 @@ class InstanceConnection extends libLink.Link {
}
class SlaveConnector extends libLink.WebSocketClientConnector {
constructor(slaveConfig, pluginInfos) {
super(slaveConfig.get("slave.master_url"), slaveConfig.get("slave.reconnect_delay"));
constructor(slaveConfig, tlsCa, pluginInfos) {
super(
slaveConfig.get("slave.master_url"),
slaveConfig.get("slave.reconnect_delay"),
tlsCa
);
this.slaveConfig = slaveConfig;
this.pluginInfos = pluginInfos;
}
@@ -1593,7 +1597,13 @@ async function startSlave() {
return;
}
let slaveConnector = new SlaveConnector(slaveConfig, pluginInfos);
let tlsCa = null;
let tlsCaPath = slaveConfig.get("slave.tls_ca");
if (tlsCaPath) {
tlsCa = await fs.readFile(tlsCaPath);
}
let slaveConnector = new SlaveConnector(slaveConfig, tlsCa, pluginInfos);
let slave = new Slave(slaveConnector, slaveConfig, pluginInfos);
// Handle interrupts
+30
View File
@@ -0,0 +1,30 @@
-----BEGIN CERTIFICATE-----
MIIFJTCCAw2gAwIBAgIUIGyavTA8+spUJ/Tb3gHmTnwXOI0wDQYJKoZIhvcNAQEL
BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTIxMDEwMzIwNTU1MFoXDTMxMDEw
MTIwNTU1MFowFDESMBAGA1UEAwwJbG9jYWxob3N0MIICIjANBgkqhkiG9w0BAQEF
AAOCAg8AMIICCgKCAgEApHfLDSqc2+kdAW8LF8Z1z68VriWEJ+wNkS7rCm8AICe/
vWYfywWDv4Kw0vzPgoGe7wmURYSS7r5i7MhFzqH4bf0B6wCIFWw2VwFqhgB94hWA
ellyIYC5ntV8RBT1RYbqSsBEJR5HKA/hFdiAf5gSIiZNnjtNT5JJLROlufD30IUQ
7teHyrbCF7/JYeVFrdisRBZg6XgMvHX6sXR4BaLkLTl6YBEe+vWkkOd9lN4pnTzG
PXSxdg4sG4QbCWsANv4bJnWuPC4rd3a/AKqonXumtBErFqluv3ylM6VY8R5E6DrQ
Wk7wjLphUXPsi8gkMAO4SY4/+CI26jFbk/5HI2baQ90jm8AOoUG6erEu5OU3a7dR
9uxIqebd9+S9FCxU9dstYiMbRcmG699Wi/mF/taWna1CdOqw7l8WRXp9q0CTqaVe
a9HdhYiSsimhOttNBD02seyKUQtUw8bw3TUeZofglqcjiP06DGH959z25NjMkiC6
b745QZ3LfzbPpSP3Ax9heHlti0Pl5LnCOIIdyk3DPDz1/xshDTXS2d18k+wpW0O0
rqOydCwzMTJjsHYYpOcqC93qfHuX/NEqNLbnOfM8SEZWqaM6ueW7tAoQc+BaHA8i
AWtgtMhFuaDrHifeIIm8FLXdyXQChL8WhpeyZa3GeSnUdCVzl+2gjSQZpaGO/fEC
AwEAAaNvMG0wHQYDVR0OBBYEFDi1Q63Txpc4NAbFf1HXlWgm+vlJMB8GA1UdIwQY
MBaAFDi1Q63Txpc4NAbFf1HXlWgm+vlJMA8GA1UdEwEB/wQFMAMBAf8wGgYDVR0R
BBMwEYIJbG9jYWxob3N0hwR/AAABMA0GCSqGSIb3DQEBCwUAA4ICAQAuOwG6NFMh
VI7ipUVsXSOBX+qTd5FnOCCTyV5UixgcDAnEZ87poH0ehI7IOia4xnhUXQsJTTaq
ho/S2hXeRuyq5Sn0RP3Zqa5IzULJWr9hQ5ajc4VuYxzhsh72gzWTJRKZRZBIL5jt
VrkS6qFG4QY4i8IAzfwDiJLhl21iEv23idbBE+yUwJNFnnuMxyllOo7fMFwB3Wij
maEaAamLd2Ocv38bstimCqtKVwg5sWMdaeELzyPtY0HnCNr1ILTW4+wMjgKwUE5z
rnwgF2d03eV2xaNY8asl5mMzJbKpz5CfD6r8KAZ2ZQM8QN+demmexZU8tMp0X3Hz
nVlBu48Ecuv5XTU1F8S2a0UoRoadIw2AtydFW6V31XtAivwrhIsz8xVkE9XiJ8c0
QpMw7bPPeQieFiSAUnRThd/5qdzeep7Vu/CtTht85rT7aqTPdPHiWUdL6x7M1Mi8
vatHGI0cvhAMXFNKAuvCFknEhUCwAKwIHfoWGsa08Kn4LhACLOd67tA45+Rdz1m5
w6Ea1zO8bfhUr/3qxod+nr9kAuN5pN3JELzIwIYGuEsp7OGWr0Wc2QRKMlDcTTIU
Xmd29Vcl5F3OwbBUmoJIqUKsENKJ0jG0DuW1svBnpRcs5wVQzPCDV/fPm3pe0c2c
KFYDk2Qa1jY9BZVyVEFJdwfVlh5iZwu0Iw==
-----END CERTIFICATE-----
+2
View File
@@ -0,0 +1,2 @@
#!/usr/bin/bash
openssl req -x509 -newkey rsa:4096 -keyout key.pem -nodes -out cert.pem -days 3650 -subj /CN=localhost -addext "subjectAltName=DNS:localhost,IP:127.0.0.1"
+52
View File
@@ -0,0 +1,52 @@
-----BEGIN PRIVATE KEY-----
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
lEgQcwoqtWDAeenVEKdo2GiojTqk9g==
-----END PRIVATE KEY-----
+8 -5
View File
@@ -134,9 +134,10 @@ before(async function() {
await exec("node ../../packages/master config set master.auth_secret TestSecretDoNotUse");
await exec("node ../../packages/master config set master.http_port 8880");
await exec("node ../../packages/master config set master.https_port 4443");
await exec("node ../../packages/master config set master.tls_bits 1024");
await exec("node ../../packages/master config set master.heartbeat_interval 0.25");
await exec("node ../../packages/master config set master.connector_shutdown_timeout 2");
await exec("node ../../packages/master config set master.tls_certificate ../../test/file/tls/cert.pem");
await exec("node ../../packages/master config set master.tls_private_key ../../test/file/tls/key.pem");
await exec("node ../../packages/ctl plugin add ../../plugins/global_chat");
await exec("node ../../packages/ctl plugin add ../../plugins/research_sync");
@@ -145,16 +146,18 @@ before(async function() {
await exec("node ../../packages/master bootstrap create-admin test");
await exec("node ../../packages/master bootstrap create-ctl-config test");
await exec("node ../../packages/ctl control-config set control.tls_ca ../../test/file/tls/cert.pem");
masterProcess = await spawn("master:", "node ../../packages/master run", /All plugins loaded/);
let createArgs = "--id 4 --name slave --generate-token";
await execCtl(`slave create-config ${createArgs}`);
await execCtl("slave create-config --id 4 --name slave --generate-token");
await exec(`node ../../packages/slave config set slave.factorio_directory ${path.join("..", "..", "factorio")}`);
await exec("node ../../packages/slave config set slave.tls_ca ../../test/file/tls/cert.pem");
slaveProcess = await spawn("slave:", "node ../../packages/slave run", /SOCKET \| registering slave/);
let controlConnector = new TestControlConnector(url, 2);
let tlsCa = await fs.readFile("test/file/tls/cert.pem");
let controlConnector = new TestControlConnector(url, 2, tlsCa);
controlConnector.token = controlToken;
control = new TestControl(controlConnector);
await controlConnector.connect();
+7 -2
View File
@@ -1,6 +1,7 @@
"use strict";
const assert = require("assert").strict;
const events = require("events");
const fs = require("fs-extra");
const jwt = require("jsonwebtoken");
const { TestControlConnector, TestControl, get, exec, url } = require("./index");
@@ -8,10 +9,14 @@ const { TestControlConnector, TestControl, get, exec, url } = require("./index")
let token = jwt.sign({ aud: "user", user: "test" }, "TestSecretDoNotUse");
describe("Integration of lib/link", function() {
let tlsCa;
let control;
let controlConnector;
before(async function() {
tlsCa = await fs.readFile("test/file/tls/cert.pem");
});
it("should emitt an error if authentication failed", async function() {
controlConnector = new TestControlConnector(url, 0.2);
controlConnector = new TestControlConnector(url, 0.2, tlsCa);
controlConnector.token = "gibberish";
control = new TestControl(controlConnector);
await assert.rejects(
@@ -21,7 +26,7 @@ describe("Integration of lib/link", function() {
});
it("should connect with proper credentials", async function() {
controlConnector = new TestControlConnector(url, 0.2);
controlConnector = new TestControlConnector(url, 0.2, tlsCa);
controlConnector.token = token;
control = new TestControl(controlConnector);
await controlConnector.connect();
-33
View File
@@ -1,33 +0,0 @@
"use strict";
const assert = require("assert");
const fs = require("fs-extra");
const path = require("path");
const generateSslCert = require("@clusterio/master/src/generate_ssl_cert");
describe("generate_ssl_cert", function() {
let testDir = path.join("temp", "test", "certTest");
before(async function() {
await fs.remove(testDir);
});
it("Creates a folder with a .crt and .key file in it", async function() {
this.timeout(1000);
// eslint-disable-next-line no-process-env
if (process.env.FAST_TEST) {
this.skip();
}
let certPath = path.join(testDir, "cert.crt");
let privKeyPath = path.join(testDir, "cert.key");
await generateSslCert({
bits: 512, // This is too small for real world usage, but faster to test
sslCertPath: certPath,
sslPrivKeyPath: privKeyPath,
});
assert(await fs.exists(certPath), "cert file was not created");
assert(await fs.exists(privKeyPath), "key file was not created");
});
});