Add remote authorization audit matrix
This commit is contained in:
parent
42d7301bdb
commit
cab0584656
2 changed files with 196 additions and 2 deletions
|
|
@ -10695,6 +10695,196 @@ mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use tokio::io::AsyncReadExt;
|
use tokio::io::AsyncReadExt;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
enum RemoteGuardKind {
|
||||||
|
Capability,
|
||||||
|
SignedLog,
|
||||||
|
OwnerReview,
|
||||||
|
CandidateOnly,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct RemoteGuardAudit {
|
||||||
|
operation: &'static str,
|
||||||
|
mutates_or_opens_service: bool,
|
||||||
|
guard: RemoteGuardKind,
|
||||||
|
resource: Option<&'static str>,
|
||||||
|
capability: Option<&'static str>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remote_guard_audit_matrix() -> Vec<RemoteGuardAudit> {
|
||||||
|
vec![
|
||||||
|
RemoteGuardAudit {
|
||||||
|
operation: "peer.ping",
|
||||||
|
mutates_or_opens_service: false,
|
||||||
|
guard: RemoteGuardKind::CandidateOnly,
|
||||||
|
resource: None,
|
||||||
|
capability: None,
|
||||||
|
},
|
||||||
|
RemoteGuardAudit {
|
||||||
|
operation: "sync.status",
|
||||||
|
mutates_or_opens_service: false,
|
||||||
|
guard: RemoteGuardKind::Capability,
|
||||||
|
resource: Some("per-stream"),
|
||||||
|
capability: Some("per-stream"),
|
||||||
|
},
|
||||||
|
RemoteGuardAudit {
|
||||||
|
operation: "keychain.sync",
|
||||||
|
mutates_or_opens_service: true,
|
||||||
|
guard: RemoteGuardKind::SignedLog,
|
||||||
|
resource: Some("keychain"),
|
||||||
|
capability: None,
|
||||||
|
},
|
||||||
|
RemoteGuardAudit {
|
||||||
|
operation: "auth.sync",
|
||||||
|
mutates_or_opens_service: true,
|
||||||
|
guard: RemoteGuardKind::SignedLog,
|
||||||
|
resource: Some("resource-auth"),
|
||||||
|
capability: None,
|
||||||
|
},
|
||||||
|
RemoteGuardAudit {
|
||||||
|
operation: "node.enrollment.submit",
|
||||||
|
mutates_or_opens_service: true,
|
||||||
|
guard: RemoteGuardKind::OwnerReview,
|
||||||
|
resource: Some("node-enrollment"),
|
||||||
|
capability: None,
|
||||||
|
},
|
||||||
|
RemoteGuardAudit {
|
||||||
|
operation: "cas.fetch",
|
||||||
|
mutates_or_opens_service: false,
|
||||||
|
guard: RemoteGuardKind::Capability,
|
||||||
|
resource: Some("resource:cas:local"),
|
||||||
|
capability: Some("cas.fetch"),
|
||||||
|
},
|
||||||
|
RemoteGuardAudit {
|
||||||
|
operation: "cas.root.sync",
|
||||||
|
mutates_or_opens_service: false,
|
||||||
|
guard: RemoteGuardKind::Capability,
|
||||||
|
resource: Some("resource:cas-tree:<name>"),
|
||||||
|
capability: Some("cas.fetch"),
|
||||||
|
},
|
||||||
|
RemoteGuardAudit {
|
||||||
|
operation: "ssh.cert.sync",
|
||||||
|
mutates_or_opens_service: false,
|
||||||
|
guard: RemoteGuardKind::Capability,
|
||||||
|
resource: Some("resource:ssh:certs"),
|
||||||
|
capability: Some("ssh_cert.sync"),
|
||||||
|
},
|
||||||
|
RemoteGuardAudit {
|
||||||
|
operation: "ssh.revocation.sync",
|
||||||
|
mutates_or_opens_service: false,
|
||||||
|
guard: RemoteGuardKind::Capability,
|
||||||
|
resource: Some("resource:ssh:revocations"),
|
||||||
|
capability: Some("ssh_revocation.sync"),
|
||||||
|
},
|
||||||
|
RemoteGuardAudit {
|
||||||
|
operation: "kv.sync",
|
||||||
|
mutates_or_opens_service: false,
|
||||||
|
guard: RemoteGuardKind::Capability,
|
||||||
|
resource: Some("resource:kv:<name>"),
|
||||||
|
capability: Some("kv.read"),
|
||||||
|
},
|
||||||
|
RemoteGuardAudit {
|
||||||
|
operation: "document.sync",
|
||||||
|
mutates_or_opens_service: false,
|
||||||
|
guard: RemoteGuardKind::Capability,
|
||||||
|
resource: Some("resource:document:<name>"),
|
||||||
|
capability: Some("document.read"),
|
||||||
|
},
|
||||||
|
RemoteGuardAudit {
|
||||||
|
operation: "db.sync",
|
||||||
|
mutates_or_opens_service: false,
|
||||||
|
guard: RemoteGuardKind::Capability,
|
||||||
|
resource: Some("resource:db:<name>"),
|
||||||
|
capability: Some("db.sync"),
|
||||||
|
},
|
||||||
|
RemoteGuardAudit {
|
||||||
|
operation: "pubsub.publish",
|
||||||
|
mutates_or_opens_service: true,
|
||||||
|
guard: RemoteGuardKind::Capability,
|
||||||
|
resource: Some("resource:pubsub:<topic>"),
|
||||||
|
capability: Some("pubsub.publish"),
|
||||||
|
},
|
||||||
|
RemoteGuardAudit {
|
||||||
|
operation: "pubsub.subscribe",
|
||||||
|
mutates_or_opens_service: false,
|
||||||
|
guard: RemoteGuardKind::Capability,
|
||||||
|
resource: Some("resource:pubsub:<topic>"),
|
||||||
|
capability: Some("pubsub.subscribe"),
|
||||||
|
},
|
||||||
|
RemoteGuardAudit {
|
||||||
|
operation: "pipe.connect",
|
||||||
|
mutates_or_opens_service: true,
|
||||||
|
guard: RemoteGuardKind::Capability,
|
||||||
|
resource: Some("resource:pipe:<name>"),
|
||||||
|
capability: Some("pipe.connect"),
|
||||||
|
},
|
||||||
|
RemoteGuardAudit {
|
||||||
|
operation: "pipe.listen",
|
||||||
|
mutates_or_opens_service: true,
|
||||||
|
guard: RemoteGuardKind::Capability,
|
||||||
|
resource: Some("resource:pipe:<name>"),
|
||||||
|
capability: Some("pipe.listen"),
|
||||||
|
},
|
||||||
|
RemoteGuardAudit {
|
||||||
|
operation: "pipe.send",
|
||||||
|
mutates_or_opens_service: true,
|
||||||
|
guard: RemoteGuardKind::Capability,
|
||||||
|
resource: Some("resource:pipe:<name>"),
|
||||||
|
capability: Some("pipe.connect"),
|
||||||
|
},
|
||||||
|
RemoteGuardAudit {
|
||||||
|
operation: "pipe.tcp.forward",
|
||||||
|
mutates_or_opens_service: true,
|
||||||
|
guard: RemoteGuardKind::Capability,
|
||||||
|
resource: Some("resource:pipe-tcp:<target>"),
|
||||||
|
capability: Some("pipe.forward"),
|
||||||
|
},
|
||||||
|
RemoteGuardAudit {
|
||||||
|
operation: "pipe.unix.forward",
|
||||||
|
mutates_or_opens_service: true,
|
||||||
|
guard: RemoteGuardKind::Capability,
|
||||||
|
resource: Some("resource:pipe-unix:<target>"),
|
||||||
|
capability: Some("pipe.forward"),
|
||||||
|
},
|
||||||
|
RemoteGuardAudit {
|
||||||
|
operation: "ssh.proxy.connect",
|
||||||
|
mutates_or_opens_service: true,
|
||||||
|
guard: RemoteGuardKind::Capability,
|
||||||
|
resource: Some("resource:ssh-proxy:local"),
|
||||||
|
capability: Some("ssh_proxy.connect"),
|
||||||
|
},
|
||||||
|
RemoteGuardAudit {
|
||||||
|
operation: "ssh.admin-shell",
|
||||||
|
mutates_or_opens_service: true,
|
||||||
|
guard: RemoteGuardKind::Capability,
|
||||||
|
resource: Some("resource:ssh-proxy:local"),
|
||||||
|
capability: Some("ssh_proxy.admin_shell"),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn remote_authorization_audit_matrix_covers_mutating_and_service_operations() {
|
||||||
|
let matrix = remote_guard_audit_matrix();
|
||||||
|
assert_eq!(matrix.len(), 21);
|
||||||
|
for item in matrix.iter().filter(|item| item.mutates_or_opens_service) {
|
||||||
|
assert_ne!(
|
||||||
|
item.guard,
|
||||||
|
RemoteGuardKind::CandidateOnly,
|
||||||
|
"{} must not rely on peer-card discovery alone",
|
||||||
|
item.operation
|
||||||
|
);
|
||||||
|
if item.guard == RemoteGuardKind::Capability {
|
||||||
|
assert!(
|
||||||
|
item.resource.is_some() && item.capability.is_some(),
|
||||||
|
"{} capability guard must document resource and capability",
|
||||||
|
item.operation
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn write_offline_iroh_config(paths: &GethPaths) {
|
fn write_offline_iroh_config(paths: &GethPaths) {
|
||||||
std::fs::write(
|
std::fs::write(
|
||||||
paths.config_file(),
|
paths.config_file(),
|
||||||
|
|
|
||||||
|
|
@ -82,8 +82,12 @@ Implementation order:
|
||||||
|
|
||||||
- `[~]` Remote authorization enforcement audit.
|
- `[~]` Remote authorization enforcement audit.
|
||||||
Acceptance criteria:
|
Acceptance criteria:
|
||||||
- `[ ]` Every remote mutable operation has an explicit resource capability
|
- `[x]` Every remote mutable operation has an explicit resource capability
|
||||||
check before mutating local state or opening a host service.
|
check before mutating local state or opening a host service, or is
|
||||||
|
documented as a signed-log import / owner-reviewed enrollment exception.
|
||||||
|
- `[x]` A test-backed remote guard matrix documents the expected guard for
|
||||||
|
each remote operation and fails if mutating/service-opening operations rely
|
||||||
|
on discovery alone.
|
||||||
- `[ ]` Tests cover denied and allowed paths for CAS, KV, DB, document,
|
- `[ ]` Tests cover denied and allowed paths for CAS, KV, DB, document,
|
||||||
pubsub, pipe, SSH proxy/admin shell, SSH cert metadata, and revocations.
|
pubsub, pipe, SSH proxy/admin shell, SSH cert metadata, and revocations.
|
||||||
- `[x]` Initial two-daemon denied-mutation coverage exists for remote pubsub
|
- `[x]` Initial two-daemon denied-mutation coverage exists for remote pubsub
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue