security(jd): add persona-only SSH closure actions
This commit is contained in:
parent
f86142b660
commit
7c3c8e9238
7 changed files with 80 additions and 1 deletions
|
|
@ -8,6 +8,62 @@ const { execFile } = require("node:child_process");
|
|||
const SOCKET_PATH = process.env.LAKE_LAMP_OWNER_ACCESS_SOCKET || "/run/guanghu-owner-access/owner-access.sock";
|
||||
const SSH_CONFIG = process.env.LAKE_LAMP_SSH_CONFIG || "/etc/guanghu/action-broker-ssh-config";
|
||||
|
||||
const INSPECT_OWNER_SSH_LOGIN = String.raw`set -eu
|
||||
test "$(id -u)" = "0"
|
||||
password=$(/usr/sbin/sshd -T | awk '$1 == "passwordauthentication" {print $2; exit}')
|
||||
keyboard=$(/usr/sbin/sshd -T | awk '$1 == "kbdinteractiveauthentication" {print $2; exit}')
|
||||
root_login=$(/usr/sbin/sshd -T | awk '$1 == "permitrootlogin" {print $2; exit}')
|
||||
printf 'PASSWORD_AUTH=%s\nKBD_INTERACTIVE_AUTH=%s\nROOT_LOGIN=%s\nSSH=%s\n' \
|
||||
"$password" "$keyboard" "$root_login" \
|
||||
"$(systemctl is-active ssh 2>/dev/null || systemctl is-active sshd)"`;
|
||||
|
||||
const DISABLE_OWNER_PASSWORD_LOGIN = String.raw`set -eu
|
||||
test "$(id -u)" = "0"
|
||||
cfg=/etc/ssh/sshd_config.d/90-guanghu-key-only.conf
|
||||
test -f "$cfg"
|
||||
backup_dir=/root/guanghu-security-backup-$(date -u +%Y%m%dT%H%M%SZ)
|
||||
mkdir -p "$backup_dir"
|
||||
chmod 0700 "$backup_dir"
|
||||
cp -a "$cfg" "$backup_dir/90-guanghu-key-only.conf.before"
|
||||
rollback() {
|
||||
cp -a "$backup_dir/90-guanghu-key-only.conf.before" "$cfg"
|
||||
/usr/sbin/sshd -t
|
||||
systemctl reload ssh 2>/dev/null || systemctl reload sshd
|
||||
}
|
||||
trap 'rc=$?; if [ "$rc" -ne 0 ]; then rollback; fi; exit "$rc"' EXIT
|
||||
/usr/bin/python3 - "$cfg" <<'PY'
|
||||
from pathlib import Path
|
||||
import re, sys
|
||||
|
||||
path = Path(sys.argv[1])
|
||||
text = path.read_text()
|
||||
for directive, value in (
|
||||
("PasswordAuthentication", "no"),
|
||||
("KbdInteractiveAuthentication", "no"),
|
||||
("PermitRootLogin", "prohibit-password"),
|
||||
):
|
||||
pattern = re.compile(rf"(?im)^\s*{directive}\s+\S+\s*$")
|
||||
replacement = f"{directive} {value}"
|
||||
if pattern.search(text):
|
||||
text = pattern.sub(replacement, text)
|
||||
else:
|
||||
text = text.rstrip() + f"\n{replacement}\n"
|
||||
path.write_text(text)
|
||||
PY
|
||||
/usr/sbin/sshd -t
|
||||
password=$(/usr/sbin/sshd -T | awk '$1 == "passwordauthentication" {print $2; exit}')
|
||||
keyboard=$(/usr/sbin/sshd -T | awk '$1 == "kbdinteractiveauthentication" {print $2; exit}')
|
||||
root_login=$(/usr/sbin/sshd -T | awk '$1 == "permitrootlogin" {print $2; exit}')
|
||||
test "$password" = "no"
|
||||
test "$keyboard" = "no"
|
||||
test "$root_login" != "yes"
|
||||
systemctl reload ssh 2>/dev/null || systemctl reload sshd
|
||||
printf 'PASSWORD_AUTH=%s\nKBD_INTERACTIVE_AUTH=%s\nROOT_LOGIN=%s\nSSH=%s\nBACKUP=%s\n' \
|
||||
"$password" "$keyboard" "$root_login" \
|
||||
"$(systemctl is-active ssh 2>/dev/null || systemctl is-active sshd)" \
|
||||
"$backup_dir/90-guanghu-key-only.conf.before"
|
||||
trap - EXIT`;
|
||||
|
||||
const RESTORE_OWNER_PASSWORD_LOGIN = String.raw`set -eu
|
||||
test "$(id -u)" = "0"
|
||||
cfg=/etc/ssh/sshd_config.d/90-guanghu-key-only.conf
|
||||
|
|
@ -171,6 +227,8 @@ async function execute(request) {
|
|||
if (!request || request.cmd || request.command || request.shell || request.args) return { ok: false, error: "arbitrary_command_forbidden" };
|
||||
if (request.target !== "JD-FD-PRIMARY") return { ok: false, error: "action_not_registered" };
|
||||
const commands = {
|
||||
"inspect-owner-ssh-login": INSPECT_OWNER_SSH_LOGIN,
|
||||
"disable-owner-password-login": DISABLE_OWNER_PASSWORD_LOGIN,
|
||||
"restore-owner-password-login": RESTORE_OWNER_PASSWORD_LOGIN,
|
||||
"restore-code-channel-owner-login": RESTORE_CODE_CHANNEL_OWNER_LOGIN,
|
||||
};
|
||||
|
|
@ -202,6 +260,8 @@ if (require.main === module) {
|
|||
|
||||
module.exports = {
|
||||
execute,
|
||||
INSPECT_OWNER_SSH_LOGIN,
|
||||
DISABLE_OWNER_PASSWORD_LOGIN,
|
||||
RESTORE_OWNER_PASSWORD_LOGIN,
|
||||
RESTORE_CODE_CHANNEL_OWNER_LOGIN,
|
||||
SOCKET_PATH,
|
||||
|
|
|
|||
Loading…
Reference in a new issue