feat(servers): add secure user, group, and SSH access management
This commit is contained in:
1 parent
f8dfe812ff
commit
7ef17105ad
15 files changed
+6043
-52
No files matched your search
@@ -0,0 +1,168 @@
|
||||
import assert from "node:assert/strict";
|
||||
import test from "node:test";
|
||||
|
||||
import {
|
||||
getSshConfigurationRevision,
|
||||
parseEffectiveSshPolicy,
|
||||
validateSshAccessPolicy,
|
||||
} from "../../src/server/services/ssh-services/internal/ssh-access-security";
|
||||
import {
|
||||
SystemAccountConflictError,
|
||||
SystemAccountInputError,
|
||||
} from "../../src/server/services/ssh-services/internal/system-account-security";
|
||||
|
||||
const basePolicy = {
|
||||
serverUsername: "deploy",
|
||||
serverAuthType: "SSH_KEY" as const,
|
||||
currentRevision: "a".repeat(64),
|
||||
expectedRevision: "a".repeat(64),
|
||||
currentPasswordAuthentication: false,
|
||||
desired: {
|
||||
pubkeyAuthentication: true,
|
||||
passwordAuthentication: false,
|
||||
permitRootLogin: "no" as const,
|
||||
permitEmptyPasswords: false as const,
|
||||
},
|
||||
temporaryMinutes: null,
|
||||
};
|
||||
|
||||
test("effective SSH policy parsing normalizes root key-only aliases", () => {
|
||||
assert.deepEqual(
|
||||
parseEffectiveSshPolicy([
|
||||
"pubkeyauthentication yes",
|
||||
"passwordauthentication no",
|
||||
"permitrootlogin without-password",
|
||||
"permitemptypasswords no",
|
||||
].join("\n")),
|
||||
{
|
||||
pubkeyAuthentication: true,
|
||||
passwordAuthentication: false,
|
||||
permitRootLogin: "prohibit-password",
|
||||
permitEmptyPasswords: false,
|
||||
},
|
||||
);
|
||||
assert.equal(
|
||||
parseEffectiveSshPolicy([
|
||||
"pubkeyauthentication yes",
|
||||
"passwordauthentication yes",
|
||||
"permitrootlogin yes",
|
||||
"permitemptypasswords yes",
|
||||
].join("\n"))?.permitEmptyPasswords,
|
||||
true,
|
||||
);
|
||||
});
|
||||
|
||||
test("SSH policy revision is stable and content-sensitive", () => {
|
||||
assert.equal(getSshConfigurationRevision("same"), getSshConfigurationRevision("same"));
|
||||
assert.notEqual(getSshConfigurationRevision("same"), getSshConfigurationRevision("changed"));
|
||||
});
|
||||
|
||||
test("SSH policy keeps the active Doktainer authentication method", () => {
|
||||
assert.doesNotThrow(() => validateSshAccessPolicy(basePolicy));
|
||||
assert.throws(
|
||||
() =>
|
||||
validateSshAccessPolicy({
|
||||
...basePolicy,
|
||||
desired: {
|
||||
...basePolicy.desired,
|
||||
pubkeyAuthentication: false,
|
||||
passwordAuthentication: true,
|
||||
},
|
||||
}),
|
||||
/uses an SSH key/i,
|
||||
);
|
||||
assert.throws(
|
||||
() =>
|
||||
validateSshAccessPolicy({
|
||||
...basePolicy,
|
||||
serverAuthType: "PASSWORD",
|
||||
desired: {
|
||||
...basePolicy.desired,
|
||||
passwordAuthentication: false,
|
||||
},
|
||||
}),
|
||||
/uses a password/i,
|
||||
);
|
||||
});
|
||||
|
||||
test("SSH policy rejects stale revisions, empty passwords, and disabling all methods", () => {
|
||||
assert.throws(
|
||||
() =>
|
||||
validateSshAccessPolicy({
|
||||
...basePolicy,
|
||||
expectedRevision: "b".repeat(64),
|
||||
}),
|
||||
SystemAccountConflictError,
|
||||
);
|
||||
assert.throws(
|
||||
() =>
|
||||
validateSshAccessPolicy({
|
||||
...basePolicy,
|
||||
desired: {
|
||||
...basePolicy.desired,
|
||||
permitEmptyPasswords: true,
|
||||
} as never,
|
||||
}),
|
||||
/must remain disabled/i,
|
||||
);
|
||||
assert.throws(
|
||||
() =>
|
||||
validateSshAccessPolicy({
|
||||
...basePolicy,
|
||||
desired: {
|
||||
...basePolicy.desired,
|
||||
pubkeyAuthentication: false,
|
||||
passwordAuthentication: false,
|
||||
},
|
||||
}),
|
||||
/at least one/i,
|
||||
);
|
||||
});
|
||||
|
||||
test("root sessions and temporary password access have lockout guards", () => {
|
||||
assert.throws(
|
||||
() =>
|
||||
validateSshAccessPolicy({
|
||||
...basePolicy,
|
||||
serverUsername: "root",
|
||||
}),
|
||||
/connects as root/i,
|
||||
);
|
||||
assert.throws(
|
||||
() =>
|
||||
validateSshAccessPolicy({
|
||||
...basePolicy,
|
||||
serverUsername: "root",
|
||||
serverAuthType: "PASSWORD",
|
||||
desired: {
|
||||
...basePolicy.desired,
|
||||
passwordAuthentication: true,
|
||||
permitRootLogin: "prohibit-password",
|
||||
},
|
||||
}),
|
||||
SystemAccountInputError,
|
||||
);
|
||||
assert.doesNotThrow(() =>
|
||||
validateSshAccessPolicy({
|
||||
...basePolicy,
|
||||
desired: {
|
||||
...basePolicy.desired,
|
||||
passwordAuthentication: true,
|
||||
},
|
||||
temporaryMinutes: 15,
|
||||
}),
|
||||
);
|
||||
assert.throws(
|
||||
() =>
|
||||
validateSshAccessPolicy({
|
||||
...basePolicy,
|
||||
currentPasswordAuthentication: true,
|
||||
desired: {
|
||||
...basePolicy.desired,
|
||||
passwordAuthentication: true,
|
||||
},
|
||||
temporaryMinutes: 15,
|
||||
}),
|
||||
/already enabled/i,
|
||||
);
|
||||
});
|
||||
Reference in new issue
Block a user