3.3 KiB
3.3 KiB
id, name, status, depends_on, scope, risk, impact, level
| id | name | status | depends_on | scope | risk | impact | level | |
|---|---|---|---|---|---|---|---|---|
| core/forwarding-policy | Implement ForwardingPolicy with rule-based allow/deny | completed |
|
moderate | low | component | implementation |
Description
Implement ForwardingPolicy with rule-based allow/deny for channel_open_direct_tcpip targets, per ADR-031 and configuration.md.
Currently, any authenticated client can open a direct-tcpip channel to any destination. ForwardingPolicy adds access control: rules are evaluated in order, first match wins, and a default action handles the fallthrough case.
Key additions:
ForwardingPolicystruct:{ default: ForwardingAction, rules: Vec<ForwardingRule> }ForwardingActionenum:Allow|DenyForwardingRulestruct:{ target: TargetPattern, action: ForwardingAction, principals: Vec<String>, transports: Vec<TransportKind> }TargetPatternenum:Any,Host(String),Cidr(IpNetwork),PortRange(String, Range<u16>)- Policy evaluation method:
ForwardingPolicy::check(&self, target: &str, port: u16, identity: &Identity, transport: TransportKind) -> bool
Key changes:
ServerHandler::channel_open_direct_tcpip()currently spawns a proxy task for any non-reserved destination. After this task, it evaluatesForwardingPolicy::check()before proxying.DynamicConfiggains aforwardingfield of typeArc<ForwardingPolicy>(already defined in config task, initiallyForwardingPolicy::allow_all())- Default
ForwardingPolicy::allow_all()preserves current behavior (migration compatibility per ADR-031) ForwardingPolicy::deny_all()for production deployments
Depends on identity-type-provider because ForwardingPolicy::check() takes &Identity to match against principals (which maps to Identity.id).
Acceptance Criteria
ForwardingPolicy,ForwardingAction,ForwardingRule,TargetPatterntypes defined incrates/alknet-core/src/config/forwarding.rsForwardingPolicy::allow_all()andForwardingPolicy::deny_all()constructorsForwardingPolicy::check()evaluates rules in order, first match wins, falls through to default- Empty
principalsfield matches all identities (no principal filter) - Empty
transportsfield matches all transport kinds TargetPattern::Hostsupports glob matching (e.g.,*.example.com)TargetPattern::Cidrmatches IP addresses within CIDR rangesTargetPattern::PortRangematches hosts with port rangesServerHandler::channel_open_direct_tcpip()callsForwardingPolicy::check()before proxying; denies with log message if policy rejects- Reserved
alknet-*destinations bypass forwarding policy (internal routing, per ADR-018) - All existing tests pass (default
allow_all()preserves current behavior) - New tests: policy evaluation with various rules, principal matching, transport matching, default fallthrough
References
- docs/architecture/decisions/031-forwarding-policy.md — ADR-031, type definitions, evaluation order
- docs/architecture/configuration.md — ForwardingPolicy in DynamicConfig
- docs/architecture/identity.md — Identity.scopes used by ForwardingPolicy
- crates/alknet-core/src/server/handler.rs — channel_open_direct_tcpip() where policy check goes
Notes
To be filled by implementation agent
Summary
To be filled on completion