- docs/architecture/: README index, overview, wire, producer, consumer, vendor, bast specs + open-questions.md (the OQ-SK-01..09 ledger promoted; new questions as OQ-SK2-06..) - ADRs 001-012: ALPN/op/params, protocol base, the handle swap, the dial-callback shape, auth split by the door, access control (open gate + BIND command gate), BIND in base, provider defaults, feature gates, channel capacity, the inline vendor, target policy - deferred OQs (SK2-06, SK2-07) with tracker tasks in tasks/architecture/ per the sdd_process deferred-OQ protocol - review pass applied: frame-length joint bound (65766 corner), accept_no_auth vs skip_auth corrected against fast-socks5 source, composed-feature wasm posture, cross-reference fixes Verified: cross-references (all ADR/OQ refs resolve), doc sizes under split threshold, Phase 0 fidelity spot-checks
3.9 KiB
ADR-006: Access-Control Posture — the Open Gate Plus the Command Gate
Status
Accepted (2026-09-20, Phase 1; scope gates POC-validated in shape —
POC #1 (socks5:open), POC #5 (socks5:bind at command dispatch))
Context
SOCKS5 is arbitrary-egress by nature — the open gate plus the target policy are the security boundary (AGENTS.md convention 12). alktunnels resolved the sibling posture (its ADR-006): whatever ACL governs the resource governs everything reachable through it, plus whatever policy the SOCKS5 implementation itself applies downstream. For SOCKS5, BIND adds an inbound capability — the accept-side twin of arbitrary egress — so the open gate must distinguish it (OQ-SK-08's security note): an identity with proxy egress must not implicitly get ingress listeners. POC #5 validated exactly this distinction at command dispatch from the per-call opener identity.
Decision
- The open gate is the boundary. The open op's
AccessControl.required_scopesis["socks5:open"](SOCKS5_OPEN_SCOPE) — scope-gated viaChannelCore::register_openable(the registry runs the ACL before the open handler). Scope-string convention:<alpn-family>:<capability>(socks5:open,socks5:bind) — following alktty'sTTY_OPEN_SCOPE/ alktunnels'tunnel:open/tunnel:directshape. Stable once published. - The command gate: BIND requires
socks5:bindat command dispatch. The open op carries the session-level gate; the command-class distinction happens in-stream, at command read, from the per-call opener identity (CF-005/CF-006): CONNECT and UDP ASSOCIATE require onlysocks5:open; TCP BIND requiressocks5:bind. An identity without it gets the RFC-faithfulConnectionNotAllowed(0x02) refusal while CONNECT still serves the same identity (POC #5 test 4). - Target policy is the dialer's concern. No target allowlists in the base crate — the dial callback refuses (per-target refusal is an RFC reply code; ADR-004's seams). The dialer-refuses shape avoids a second policy layer (alktunnels OQ-TN-08's resolution pattern, evidence-backed). Whatever ACL governs the socks5 resource governs everything reachable through it, plus whatever the dial callback enforces.
- Per-target ACL for the composed egress comes free: each
destination rides its own alktunnels direct-op channel governed
by the
tunnel:directgrant's ACL (POC #2 validated); the dial callback governs per-destination checks. - Ownership: optionally consult
OwnershipProviderfor resource ownership (alknet ADR-050's seam) — a registration-time choice, not a protocol concern. - Hub relaying: the hub's terminate-and-re-produce applies per
hop (alkcall ADR-051's
ChannelRelay/HubLegTemplate); the hub's ACL governs the final dial — the hub is the network boundary. No socks5-specific relay work.
Consequences
- Two grants, clean separation:
socks5:open(egress) andsocks5:bind(ingress listeners) — never implied by each other (the alktunnels ADR-006 Amendment 1 posture: a capability on its own scope). - BIND's security boundary is enforced even though BIND rides the same op (ADR-001): the command gate is the mechanism, and it is POC-validated (POC #5).
- The allowlist-hook variant (a declarative per-target policy at registration) is not shipped in v1 — the dial callback is the policy point; see OQ-SK-05's residue (OQ-SK2-07 in the tracker) for the virtual-subnet translation-layer proposal, which is the same dial-callback shape.
References
- OQ-SK-05 (target policy), OQ-SK-08 (the BIND security note)
- POC #1 (the
socks5:opengate; the identity seam), POC #5 (thesocks5:bindcommand gate), POC #2 (composed per-target ACL) - alktunnels ADR-006 + Amendment 1 (the sibling posture), alknet ADR-024 (registry layering), alknet ADR-050 (ownership), alkcall ADR-042 / ADR-051 (hub relay)