Step 14: SSH key auth for gRPC.

Server: AuthInterceptor parses authorized_keys, extracts SSH signature
from gRPC metadata (nonce + timestamp signed by client's SSH key),
verifies against authorized public keys with 5-minute timestamp window.

Client: SSHCredentials implements PerRPCCredentials, signs nonce+timestamp
per request. LoadSigner resolves key from flag, ssh-agent, or default paths.

8 tests: valid auth, reject unauthenticated, reject unauthorized key,
reject expired timestamp, metadata generation, plus 2 integration tests
(authenticated succeeds, unauthenticated rejected).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-23 23:58:09 -07:00
parent 525c3f0b4f
commit 4b841cdd82
7 changed files with 621 additions and 6 deletions

View File

@@ -148,10 +148,11 @@ Depends on Step 12.
### Step 14: SSH Key Auth
- [ ] `server/auth.go`: AuthInterceptor, parse authorized_keys, verify SSH signatures
- [ ] `client/auth.go`: LoadSigner (ssh-agent or key file), PerRPCCredentials
- [ ] `server/auth_test.go`: in-memory ed25519 key pair, reject unauthenticated
- [ ] `client/auth_test.go`: metadata generation test
- [x] `server/auth.go`: AuthInterceptor, parse authorized_keys, verify SSH signatures
- [x] `client/auth.go`: LoadSigner (ssh-agent or key file), SSHCredentials (PerRPCCredentials)
- [x] `server/auth_test.go`: valid key, reject unauthenticated, reject unauthorized key, reject expired timestamp
- [x] `client/auth_test.go`: metadata generation, no-transport-security
- [x] Integration tests: authenticated push/pull succeeds, unauthenticated is rejected
### Step 15: CLI Wiring + Prune