Skip to main content

sysknife_daemon/actions/
ssh.rs

1use super::{command_mechanism, ActionSpec};
2use sysknife_types::RiskLevel;
3
4pub fn specs() -> Vec<ActionSpec> {
5    vec![
6        get_authorized_keys("alice"),
7        add_authorized_key("alice", "ssh-ed25519 AAAA..."),
8        remove_authorized_key("alice", "ssh-ed25519 AAAA..."),
9        set_sshd_option("PermitRootLogin", "prohibit-password"),
10    ]
11}
12
13/// Installed root-owned helper, with an independent option/value allowlist.
14const SSHD_OPTION_HELPER: &str = "/usr/lib/sysknife/sshd-option-edit";
15
16/// Validate a drop-in with sshd -t before reloading; roll back on rejection.
17pub fn set_sshd_option(option: &str, value: &str) -> ActionSpec {
18    ActionSpec {
19        action_name: "SetSshdOption",
20        mechanism: command_mechanism(
21            "sudo",
22            [SSHD_OPTION_HELPER, "--option", option, "--value", value],
23        ),
24        risk_level: RiskLevel::High,
25        reboot_required: false,
26        rollback_available: false,
27    }
28}
29
30pub fn get_authorized_keys(username: &str) -> ActionSpec {
31    ActionSpec {
32        action_name: "GetAuthorizedKeys",
33        mechanism: command_mechanism("cat", [&format!("/home/{username}/.ssh/authorized_keys")]),
34        risk_level: RiskLevel::Low,
35        reboot_required: false,
36        rollback_available: false,
37    }
38}
39
40/// The fixed helper operation resolves the account and drops supplementary
41/// groups, GID and UID before any access to its authorized_keys. It never accepts
42/// a caller-selected path. Keys are compared as literal whole lines, never regex
43/// patterns, and edits retain the existing inode, owner and mode (#145).
44fn keys_edit_as_user(
45    action_name: &'static str,
46    username: &str,
47    operation: &str,
48    public_key: &str,
49) -> ActionSpec {
50    ActionSpec {
51        action_name,
52        mechanism: command_mechanism(
53            "sudo",
54            [
55                "/usr/lib/sysknife/action-steps",
56                operation,
57                username,
58                public_key,
59            ],
60        ),
61        risk_level: RiskLevel::High,
62        reboot_required: false,
63        rollback_available: false,
64    }
65}
66
67pub fn add_authorized_key(username: &str, public_key: &str) -> ActionSpec {
68    keys_edit_as_user("AddAuthorizedKey", username, "ssh-add", public_key)
69}
70
71pub fn remove_authorized_key(username: &str, public_key: &str) -> ActionSpec {
72    keys_edit_as_user("RemoveAuthorizedKey", username, "ssh-remove", public_key)
73}