Sync architecture specs with Phase 2 research findings

- Add definitions.md: normative terminology disambiguation (Interface, Service,
  Transport, Token, Identity, Domain, Scope, CredentialProvider, etc.)
- Add credentials.md: CredentialProvider trait and CredentialSet enum for
  outbound auth, mirroring IdentityProvider pattern for inbound auth
- Rewrite interface.md: StreamInterface/MessageInterface split (ADR-035),
  InterfaceRequest/InterfaceResponse, HttpInterface/DnsInterface stubs,
  ListenerConfig with Stream/Http/Dns variants, credential presentation table
- Update auth.md: API keys in DynamicConfig (ADR-037), credential presentation
  per (Transport, Interface) pair, ApiKeyEntry struct in AuthPolicy
- Update configuration.md: API keys, ListenerConfig with Http/Dns variants,
  expanded TOML config examples
- Update call-protocol.md: resolve OQ-IF-01 (InterfaceEvent carries
  EventEnvelope + Identity), add MessageInterface awareness to protocol
  adapter layer
- Update overview.md: three-layer model now includes StreamInterface/
  MessageInterface, CredentialProvider/CredentialSet exports, definitions.md
  reference, ADRs 035-037
- Update open-questions.md: resolve OQ-IF-01, OQ-IF-02, add OQ-P2-01
  through OQ-P2-04, add OQ-CP-01 through OQ-CP-04, add OQ-DEF-01,
  OQ-DEF-03, OQ-DEF-08
- Update README.md: add definitions.md, credentials.md, ADRs 035-037,
  phase2 research docs, current state description

Key architectural decisions:
- ADR-035: StreamInterface/MessageInterface split (two Layer 2 traits)
- ADR-036: CredentialProvider as core type (outbound auth, alknet_core::credentials)
- ADR-037: API keys as DynamicConfig auth (hash-verified bearer tokens)
This commit is contained in:
2026-06-09 08:09:45 +00:00
parent d1af216334
commit cfc44008d3
12 changed files with 1314 additions and 151 deletions

View File

@@ -42,16 +42,30 @@ is the default implementation (reads from `DynamicConfig.auth`). `AuthProtocol`
irpc service is one way to satisfy the trait, behind a feature flag. Both paths
produce the same `Identity` result. See ADR-028 and ADR-029.
### Auth Presentation Per Transport
### Credential Presentation Per Interface
| Transport | Auth presentation | Verification |
|-----------|-------------------|-------------|
| SSH (TCP, TLS, iroh) | SSH public key auth in the SSH handshake | `ServerAuthConfig::authenticate_publickey()` — key lookup in authorized set |
| WebTransport (HTTP/3) | Signed timestamp token in CONNECT request | Token auth — same authorized set verifies the Ed25519 signature |
| Future (WebSocket, etc.) | Signed timestamp token in headers/query | Same token verification |
Each (Transport, Interface) pair presents credentials differently, but all
resolve to the same `Identity` through `IdentityProvider`. See
[definitions.md](definitions.md) for the full terminology rules.
The **key material is shared**. The **presentation differs per transport**. The
**verification result is the same**: an authenticated identity with scopes.
| (Transport, Interface) | Credential presentation | Resolves via |
|------------------------|------------------------|-------------|
| (TLS, SshInterface) | SSH public key handshake | `resolve_from_fingerprint()` |
| (TCP, SshInterface) | SSH public key handshake | `resolve_from_fingerprint()` |
| (iroh, SshInterface) | SSH public key handshake | `resolve_from_fingerprint()` |
| (TLS, RawFramingInterface) | AuthToken in frame header | `resolve_from_token()` |
| (TCP, RawFramingInterface) | AuthToken in frame header | `resolve_from_token()` |
| (WebTransport, RawFramingInterface) | AuthToken in CONNECT request | `resolve_from_token()` |
| (—, HttpInterface) | `Authorization: Bearer` header | `resolve_from_token()` |
| (—, DnsInterface) | AuthToken in query labels | `resolve_from_token()` |
The **key material is shared**. The **credential presentation** differs per
(Transport, Interface) pair. The **verification result is the same**: an
authenticated `Identity` with scopes.
`resolve_from_token()` handles both AuthTokens (Ed25519-signed) and API keys
(hash-verified bearer tokens). The implementation discriminates by prefix or
format — see ADR-037.
### Token Authentication
@@ -112,14 +126,46 @@ irpc path produce the same `Identity` result.
The trait is the contract. The backing store is pluggable. Alknet-core never
depends on Honker, SQLite, or any specific database.
### API Keys
For service accounts, automation, and HTTP interface auth, Ed25519 AuthTokens
are inconvenient — they require client-side key generation and signing. API keys
provide a simpler bearer token format (ADR-037):
```
API key: "alk_dGhlX3NlY3JldA" (~20 chars, configurable prefix)
Storage: SHA-256 hash of the full key
Lookup: prefix match → hash verification → Identity
```
API keys are configured in `DynamicConfig.auth.api_keys`:
```toml
[[auth.api_keys]]
prefix = "alk_"
hash = "sha256:abc..."
scopes = ["relay:connect"]
description = "dashboard service account"
ttl = "30d" # optional
```
Both AuthTokens and API keys go through `IdentityProvider::resolve_from_token()`.
The implementation discriminates by prefix (default `alk_`): if the token starts
with the API key prefix, it's verified by SHA-256 hash lookup; otherwise, it's
verified as an Ed25519 AuthToken. Both paths produce the same `Identity`.
See [configuration.md](configuration.md) for the full `DynamicConfig.auth`
structure and ADR-037 for the decision context.
### AuthPolicy Structure
`AuthPolicy` in `DynamicConfig` holds both auth paths, sharing key material:
`AuthPolicy` in `DynamicConfig` holds all auth paths, sharing key material:
```rust
pub struct AuthPolicy {
pub ssh: SshAuthConfig,
pub token: TokenAuthConfig,
pub api_keys: Vec<ApiKeyEntry>,
}
pub struct SshAuthConfig {
@@ -142,6 +188,14 @@ pub enum TokenKeySource {
/// For deployments that want distinct access control per transport.
Separate(HashSet<PublicKey>),
}
pub struct ApiKeyEntry {
pub prefix: String, // e.g., "alk_"
pub hash: String, // e.g., "sha256:abc..."
pub scopes: Vec<String>, // e.g., ["relay:connect", "secrets:derive"]
pub description: Option<String>, // e.g., "dashboard service account"
pub expires_at: Option<u64>, // Unix timestamp, optional TTL
}
```
When `TokenKeySource::Shared` (the default), adding a key to
@@ -220,6 +274,13 @@ dependencies needed.
- Token auth is only available on transports that carry HTTP metadata (URL
path, headers). SSH-over-TCP/TLS/iroh continues to use SSH native auth
exclusively.
- API keys are bearer tokens — anyone who obtains the key has the associated
permissions. The hash storage and optional TTL mitigate but do not eliminate
this risk. Ed25519 AuthTokens remain the preferred auth method for interactive
clients. See ADR-037.
- API keys are verified by SHA-256 hash lookup in `DynamicConfig.auth.api_keys`
(or the `api_keys` database table in production). The full key is provided to
the client exactly once at creation time.
### Security Considerations
@@ -254,6 +315,8 @@ security consideration:
| [023](decisions/023-unified-auth-shared-key-material.md) | Unified auth, shared key material | Same keys for SSH and token auth |
| [028](decisions/028-auth-irpc-service.md) | Auth as irpc service | AuthProtocol behind feature flag; IdentityProvider is the contract |
| [029](decisions/029-identity-core-type.md) | Identity as core type | `Identity` and `IdentityProvider` in alknet-core |
| [035](decisions/035-streaminterface-messageinterface-split.md) | StreamInterface/MessageInterface | Credential presentation differs per (Transport, Interface) pair |
| [037](decisions/037-api-keys-dynamic-config.md) | API keys in DynamicConfig | Hash-verified bearer tokens for service accounts |
## References
@@ -261,6 +324,8 @@ security consideration:
- [server.md](server.md) — Current SSH auth handler
- [transport.md](transport.md) — Transport abstraction
- [configuration.md](configuration.md) — DynamicConfig, AuthPolicy, ConfigReloadHandle
- [interface.md](interface.md) — Credential presentation per (Transport, Interface) pair
- [definitions.md](definitions.md) — Terminology disambiguation (IdentityProvider vs CredentialProvider, AuthToken vs API key)
- [services.md](services.md) — AuthProtocol irpc service
- [open-questions.md](open-questions.md) — OQ-17 (resolved), OQ-18 (resolved), OQ-19
- [wtransport](https://github.com/BiagioFesta/wtransport) — Rust WebTransport library