Skip to content

feat(auth): add authentication and authorization system#106

Merged
slow2342 merged 1 commit into
mainfrom
feat/auth
Jun 10, 2026
Merged

feat(auth): add authentication and authorization system#106
slow2342 merged 1 commit into
mainfrom
feat/auth

Conversation

@slow2342

Copy link
Copy Markdown
Owner

Summary

Add full RBAC authentication and authorization system with JWT tokens, argon2id password hashing, and Raft-replicated state. Integrates permission checks into KV, Watch, Lease, and Cluster services.

Changes

  • proto/auth.proto — Auth service definitions (17 RPCs) with ResponseHeader
  • src/auth/ — User, Role, Permission, TokenValidator, AuthCache, AuthInterceptor
  • src/api/auth.rs — AuthService gRPC implementation
  • src/api/kv.rs — Permission checks on Put/Get/Delete/Range/Txn
  • src/api/watch.rs — Watch permission checks with stale credential detection
  • src/api/lease.rs — require_root on KeepAlive and Leases
  • src/api/cluster.rs — require_root fix (ok_or_else)
  • src/raft/state_machine.rs — Auth apply logic with bootstrap flag, idempotent disable
  • src/main.rs — Auth startup, random signing key generation with 0600 permissions
  • src/config.rs — AuthConfig fields
  • src/error.rs — AuthError type
  • tests/auth_test.rs — Auth integration tests

Security hardening

  • Random JWT signing key persisted with 0600 permissions
  • Bootstrap flag prevents unauthenticated re-enable after auth_disable
  • Password max length (1024 bytes) prevents argon2 CPU exhaustion
  • User/role name validation (null bytes, length, aether prefix)
  • Rate limiting on authenticate and auth_enable
  • Constant-time error messages prevent username enumeration
  • AuthStatus requires authentication when auth is enabled
  • Watch streams detect auth re-enable and reject stale credentials
  • auth_disable is idempotent
  • Error messages redact key values

How to verify

cargo build
cargo test --all-targets
cargo clippy -- -D warnings
cargo fmt -- --check

Refs #80

Implement full RBAC auth with JWT tokens, argon2id password hashing,
and Raft-replicated state. Includes 15+ security hardening fixes from
multi-pass review.

Components:
- proto/auth.proto: Auth service definitions with ResponseHeader
- src/auth/: User, Role, Permission, TokenValidator, AuthCache, AuthInterceptor
- src/api/auth.rs: AuthService gRPC implementation (17 RPCs)
- src/raft/state_machine.rs: Auth apply logic with bootstrap flag
- Permission checks integrated into KV, Watch, Lease, Cluster services

Security hardening:
- Random JWT signing key with 0600 permissions, persisted to .signing_key
- Bootstrap flag prevents unauthenticated auth_enable after auth_disable
- Password max length (1024 bytes) prevents argon2 CPU exhaustion
- User/role name validation (null bytes, length, _aether_ prefix)
- Rate limiting on authenticate and auth_enable endpoints
- Constant-time error messages prevent username enumeration
- AuthStatus requires authentication when auth is enabled
- Watch streams detect auth re-enable and reject stale credentials
- auth_disable is idempotent
- Error messages redact key values
@slow2342
slow2342 merged commit 96ee50a into main Jun 10, 2026
4 of 8 checks passed
@slow2342
slow2342 deleted the feat/auth branch June 10, 2026 16:43
Comment thread src/auth/user.rs

#[test]
fn test_hash_and_verify() {
let hash = User::hash_password(b"secret123").unwrap();
Comment thread src/auth/user.rs

#[test]
fn test_different_hashes_for_same_password() {
let h1 = User::hash_password(b"same").unwrap();
Comment thread src/auth/user.rs
#[test]
fn test_different_hashes_for_same_password() {
let h1 = User::hash_password(b"same").unwrap();
let h2 = User::hash_password(b"same").unwrap();
Comment thread tests/auth_test.rs
let validator = TokenValidator::new("test-secret", 24);

// 2. Create root user
let root_hash = User::hash_password(b"root-password-123").unwrap();
Comment thread tests/auth_test.rs
cache.insert_role(app_role);

// 4. Create a user and grant the role
let alice_hash = User::hash_password(b"alice-password").unwrap();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants