feat(dgw): persist agent tunnel authorization - #1958
feat(dgw): persist agent tunnel authorization#1958irvingouj@Devolutions (irvingoujAtDevolution) wants to merge 4 commits into
Conversation
Record the human-owned authorization, enrollment, routing, and deletion contracts that the stable Agent Tunnel implementation must preserve. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Persist accepted Agent identities and public-key bindings so deletion remains effective across Gateway restarts. Gate tunnel admission on the stored identity and SPKI, close live connections on deletion, and include offline accepted Agents in the management endpoints. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Let maintainers know that an action is required on their side
|
Acquire Agent authorization write transactions immediately to avoid read-to-write upgrade failures under SQLite WAL contention. Distinguish rejected credentials from authorization store failures and close each connection with an explicit reason. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds durable Agent tunnel authorization so enrollment, deletion, and identity-key validation survive Gateway restarts.
Changes:
- Adds a CA-bound libSQL authorization store.
- Enforces Agent ID/SPKI authorization and same-key certificate renewal.
- Updates management APIs, documentation, and integration tests.
Reviewed changes
Copilot reviewed 18 out of 19 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
testsuite/tests/cli/agent/tunnel.rs |
Tests offline listing and durable deletion. |
testsuite/tests/agent_tunnel/integration.rs |
Tests renewal key restrictions. |
testsuite/tests/agent_tunnel/common.rs |
Adds authorization-aware test setup. |
testsuite/Cargo.toml |
Adds test storage dependency. |
docs/adr/0001-authorize-agent-identities-with-an-allowlist.md |
Records authorization design. |
devolutions-gateway/tests/token_security.rs |
Allows enrollment-token retries. |
devolutions-gateway/src/token.rs |
Delegates enrollment replay protection. |
devolutions-gateway/src/service.rs |
Initializes persistent authorization storage. |
devolutions-gateway/src/api/tunnel.rs |
Persists enrollment and exposes offline Agents. |
devolutions-gateway/Cargo.toml |
Adds storage crate dependency. |
crates/agent-tunnel/src/listener.rs |
Enforces authorization during tunnel admission. |
crates/agent-tunnel/src/lib.rs |
Exports authorization interfaces. |
crates/agent-tunnel/src/cert.rs |
Adds CA loading and SPKI helpers. |
crates/agent-tunnel/src/authorization.rs |
Defines authorization-store contracts. |
crates/agent-tunnel/agent-tunnel.intent.md |
Documents Agent tunnel intent. |
crates/agent-tunnel-libsql/src/lib.rs |
Implements durable authorization storage. |
crates/agent-tunnel-libsql/migrations/01_agent_authorization.sql |
Defines the initial schema. |
crates/agent-tunnel-libsql/Cargo.toml |
Configures the new crate. |
Cargo.lock |
Locks the new workspace package. |
💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
|
||
| ## Technical Background | ||
|
|
||
| #### Enrollment Process |
| let outcome = handle | ||
| .enroll(agent_tunnel::authorization::EnrollmentAttempt { | ||
| token_id: jti, | ||
| token_expires_at: exp, | ||
| agent_id, |
| let accepted = match authorization_store.authorize(agent_id, client_spki_sha256).await { | ||
| Ok(Some(accepted)) => accepted, | ||
| Ok(None) => { | ||
| warn!(%agent_id, %peer_addr, "Rejecting Agent connection: credential is not accepted"); | ||
| conn.close(0u32.into(), b"agent-not-accepted"); |
Log the full Agent authorization error chain so operators can identify the underlying database failure. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Persists accepted Agent identities and authorized public keys so deleting an Agent remains effective after Gateway restarts.
Gateway now admits tunnel connections only when the certificate Agent ID and SPKI match stored authorization. Deleting an Agent removes that authorization before closing its live tunnel connection, and management endpoints continue to list accepted Agents while offline.
Existing pre-stable Agents must be re-enrolled after upgrading.
Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com