mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-15 23:24:52 +09:00
Replace host tokens with host pairing
Hosts join the cluster by running the installer, which shows a code and waits until the request is approved under Hosts > Add host in the web interface or with clusterioctl host approve. An admin can pass their user token to the installer to approve the host right away. The token is only used for that and is not saved. The controller only accepts hosts that have a record, and only approving a host creates one. Revoking a host deletes its record, so its token can no longer be used to reconnect. Hosts that have connected before keep working. Removes host generate-token, revoke-token and create-config from clusterioctl, bootstrap generate-host-token, the host token messages and the core.host.generate_token, revoke_token and create_config permissions, which are also stripped from stored roles. Adds clusterioctl host pending, approve, reject and revoke, and the core.host.approve and core.host.revoke permissions. Standalone installs add the host to the controller database directly, since the controller is not running during the install.
This commit is contained in:
49 files changed
+4855
-473
No files matched your search
@@ -32,6 +32,8 @@ import readline from "node:readline";
|
||||
import util from "node:util";
|
||||
|
||||
import { loadBreaks, matchBreaks, selectBreaks } from "./version-compat-breaks.js";
|
||||
// Only uses Node builtins, so it does not load a second copy of the lib.
|
||||
import { pairHost, PairingError } from "../packages/create/pair.js";
|
||||
|
||||
const execFile = util.promisify(child_process.execFile);
|
||||
|
||||
@@ -279,6 +281,44 @@ async function pollCtl(ctl, cliArgs, expectRegex, description, timeoutMs = 30e3)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pair the host with the running controller and write its config
|
||||
*
|
||||
* The pairing API is probed instead of checking which side is local, as releases that support
|
||||
* pairing no longer have ctl host create-config to fall back on.
|
||||
*
|
||||
* @returns true if the host was paired, false if the controller predates host pairing.
|
||||
*/
|
||||
async function pairHostWithController() {
|
||||
// Written by bootstrap create-ctl-config, holds the admin token which approves the host directly.
|
||||
const ctlConfig = JSON.parse(await fs.readFile(path.join(controllerDir, "config-ctl.json"), "utf8"));
|
||||
const controllerUrl = ctlConfig["ctl.controller_url"];
|
||||
console.log(`| pairing host with ${controllerUrl}`);
|
||||
let pairing;
|
||||
try {
|
||||
pairing = await pairHost({ controllerUrl, name: "host", token: ctlConfig["ctl.controller_token"] });
|
||||
} catch (err) {
|
||||
if (err instanceof PairingError && err.status === 404) {
|
||||
console.log("| controller does not support host pairing");
|
||||
return false;
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
console.log(`| paired host ${pairing.name} with id ${pairing.hostId}`);
|
||||
|
||||
// The same fields the installer sets, which every host version reads.
|
||||
const hostConfig = {
|
||||
"host.id": pairing.hostId,
|
||||
"host.name": pairing.name,
|
||||
"host.controller_url": controllerUrl,
|
||||
"host.controller_token": pairing.token,
|
||||
};
|
||||
await fs.writeFile(
|
||||
path.join(hostDir, "config-host.json"), JSON.stringify(hostConfig, null, "\t"), { flag: "wx", mode: 0o600 }
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const options = parseArgs();
|
||||
const breaks = await loadBreaks();
|
||||
@@ -337,10 +377,12 @@ async function main() {
|
||||
);
|
||||
|
||||
try {
|
||||
await run("ctl", ctl, [
|
||||
"host", "create-config", "--id", "1", "--name", "host", "--generate-token",
|
||||
"--output", path.join(hostDir, "config-host.json"),
|
||||
], controllerDir);
|
||||
if (!await pairHostWithController()) {
|
||||
await run("ctl", ctl, [
|
||||
"host", "create-config", "--id", "1", "--name", "host", "--generate-token",
|
||||
"--output", path.join(hostDir, "config-host.json"),
|
||||
], controllerDir);
|
||||
}
|
||||
|
||||
// Started host is only logged after the connection to the controller is established.
|
||||
const hostProc = await spawnDaemon("host", host, ["run"], hostDir, /Started host/);
|
||||
|
||||
Reference in new issue
Block a user