Implementation Status: 🔵 Proposed
Bootstrap and Access Control
This design document describes the bootstrap mechanism for requesting access to databases and the wildcard permission system for open access.
Overview
Bootstrap provides a "knocking" mechanism for clients to request access to databases they don't have permissions for. Wildcard permissions provide an alternative for databases that want to allow open access without requiring bootstrap requests.
Problem Statement
When a client wants to sync a database they don't have access to:
- No Direct Access: Client's key is not in the database's auth settings
- Need Permission Grant: Requires an admin to add the client's key
- Coordination Challenge: Client and admin need a way to coordinate the access grant
- Public Databases: Some databases should be openly accessible without coordination
Proposed Solution
Two complementary mechanisms:
- Wildcard Permissions: For databases that want open access
- Bootstrap Protocol: For databases that want controlled access grants
Wildcard Permissions
Wildcard Key
A database can grant universal permissions by setting the special "*" key in its auth settings:
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AuthSettings {
/// Maps SigKey → AuthKey
/// Special key "*" grants permissions to all clients
keys: HashMap<String, AuthKey>,
}
How It Works
When a client attempts to sync a database:
- Check for wildcard key: If
"*"exists in_settings.auth, grant the specified permission to any client - No key required: Client doesn't need their key in the database's auth settings
- Immediate access: No bootstrap request or approval needed
Use Cases
Public Read Access: Set wildcard key with Read permission to allow anyone to read the database. Clients can sync immediately without bootstrap.
Open Collaboration: Set wildcard key with Write permission to allow anyone to write (use carefully).
Hybrid Model: Combine wildcard Read permission with specific Write/Admin permissions for named keys. This allows public read access while restricting modifications to specific users.
Security Considerations
- Use sparingly: Wildcard permissions bypass authentication
- Read-only common: Most appropriate for public data
- Write carefully: Wildcard write allows any client to modify the database
- Per-database: Each database controls its own wildcard settings
Bootstrap Protocol
Overview
Bootstrap provides a request/approval workflow for controlled access grants:
Client Server User (with Admin key)
| | |
|-- Sync Request -------→ | |
| |-- Check Auth Settings |
| | (no matching key) |
| | |
|←- Auth Required --------| (if no global permissions) |
| | |
|-- Bootstrap Request --→ | |
| (with key & perms) | |
| |-- Store in _sync DB -------→|
| | |
|←- Request Pending ------| (Bootstrap ID returned) |
| | |
| [Wait for approval] | |
| | |
| | ←-- List Pending -|
| | --- Pending [] -->|
| | |
| | ←-- Approve ------|
| |←- Add Key to DB Auth -------|
| | (using user's Admin key) |
| | |
|-- Retry Normal Sync --→ | |
| |-- Check Auth (now has key) |
|←- Sync Success ---------| (access granted) |
Client Bootstrap Request
When a client needs access to a database:
- Client attempts normal sync
- If auth is required, client calls
sync_with_peer_for_bootstrap()with key name and requested permission - Server stores bootstrap request in
_syncdatabase - Client receives pending status and waits for approval
Bootstrap Request Storage
Bootstrap requests are stored in the _sync database:
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct BootstrapRequest {
/// Database being requested
pub tree_id: ID,
/// Client's public key (for verification)
pub requesting_pubkey: String,
/// Client's key name (to add to auth settings)
pub requesting_key_name: String,
/// Permission level requested
pub requested_permission: Permission,
/// When request was made
pub timestamp: String,
/// Current status
pub status: RequestStatus,
/// Client's network address
pub peer_address: Address,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum RequestStatus {
Pending,
Approved,
Rejected,
}
Approval by User with Admin Permission
Any logged-in user who has a key with Admin permission for the database can approve the request:
- User logs in with
instance.login_user() - Lists pending requests with
user.pending_bootstrap_requests(&sync) - User selects a key they own that has Admin permission on the target database
- Calls
user.approve_bootstrap_request(&mut sync, request_id, approving_key_id) - System validates the user owns the specified key
- System retrieves the signing key from the user's key manager
- System explicitly validates the key has Admin permission on the target database
- Creates transaction using the user's signing key
- Adds requesting key to database's auth settings
- Updates request status to Approved in the sync database
Permission Validation Strategy
Bootstrap approval and rejection use explicit permission validation:
-
Approval: The system explicitly checks that the approving user has Admin permission on the target database before adding the requesting key. This provides clear error messages (
InsufficientPermission) and fails fast if the user lacks the required permission. -
Rejection: The system explicitly checks that the rejecting user has Admin permission on the target database before allowing rejection. Since rejection only modifies the sync database (not the target database), explicit validation is necessary to enforce the Admin permission requirement.
Rationale: Explicit validation provides:
- Clear, informative error messages for users
- Fast failure before attempting database modifications
- Consistent permission checking across both operations
- Better debugging experience when permission issues occur
Client Retry After Approval
Once approved, the client retries with normal sync after waiting or polling periodically. If access was granted, the sync succeeds and the client can use the database.
Key Requirements
For Bootstrap Request:
- Client must have generated a keypair
- Client specifies the permission level they're requesting
For Approval:
- User must be logged in
- User must have a key with Admin permission for the target database
- That key must be in the database's auth settings
For Rejection:
- User must be logged in
- User must have a key with Admin permission for the target database
- That key must be in the database's auth settings
- System explicitly validates Admin permission before allowing rejection
Design Decisions
No Auto-Approval
Previous designs included auto-approval based on database policy. This has been removed in favor of:
- Global Permissions: Use wildcard
"*"key for open access - Manual Approval: All bootstrap requests require explicit approval by a user with Admin permission
Rationale:
- Simpler architecture (no policy evaluation)
- Clearer security model (explicit user actions)
- Global permissions handle "open access" use case
- Bootstrap is for controlled access grants by authorized users
Auto-approval will be removed once the new system is completed.
API Design
Wildcard Permissions API
impl SettingsStore {
/// Set wildcard permissions for database
pub fn set_wildcard_permission(&self, permission: Permission) -> Result<()>;
/// Remove wildcard permissions
pub fn remove_wildcard_permission(&self) -> Result<()>;
/// Check if database has wildcard permissions
pub fn get_wildcard_permission(&self) -> Result<Option<Permission>>;
}
Bootstrap API
impl Sync {
/// List pending bootstrap requests
pub fn pending_bootstrap_requests(&self) -> Result<Vec<(String, BootstrapRequest)>>;
/// Get specific bootstrap request
pub fn get_bootstrap_request(&self, request_id: &str) -> Result<Option<BootstrapRequest>>;
}
impl User {
/// Get all pending bootstrap requests from the sync system
pub fn pending_bootstrap_requests(
&self,
sync: &Sync,
) -> Result<Vec<(String, BootstrapRequest)>>;
/// Approve a bootstrap request (requires Admin permission)
/// The approving_key_id must be owned by this user and have Admin permission on the target database
pub fn approve_bootstrap_request(
&self,
sync: &mut Sync,
request_id: &str,
approving_key_id: &str,
) -> Result<()>;
/// Reject a bootstrap request (requires Admin permission)
/// The rejecting_key_id must be owned by this user and have Admin permission on the target database
pub fn reject_bootstrap_request(
&self,
sync: &mut Sync,
request_id: &str,
rejecting_key_id: &str,
) -> Result<()>;
}
// Client-side bootstrap request
impl Sync {
/// Request bootstrap access to a database
pub async fn sync_with_peer_for_bootstrap(
&self,
peer_addr: &Address,
tree_id: &ID,
key_name: &str,
requested_permission: Permission,
) -> Result<()>;
}
Security Considerations
Wildcard Permissions
- Public Exposure: Wildcard permissions make databases publicly accessible
- Write Risk: Wildcard write allows anyone to modify data
- Audit Trail: All modifications still signed by individual keys
- Revocation: Can remove wildcard permission at any time
Bootstrap Protocol
- Request Validation: Verify requesting public key matches signature
- Permission Limits: Clients request permission, approving user decides what to grant
- Admin Permission Required: Only users with Admin permission on the database can approve
- Request Expiry: Consider implementing request expiration
- Rate Limiting: Prevent spam bootstrap requests
Implementation Strategy
Phase 1: Wildcard Permissions
- Update AuthSettings to support
"*"key - Modify sync protocol to check for wildcard permissions
- Add SettingsStore API for wildcard management
- Tests for wildcard permission scenarios
Phase 2: Bootstrap Request Storage
- Define BootstrapRequest structure
- Implement storage in
_syncdatabase - Add request listing and retrieval APIs
- Tests for request storage and retrieval
Phase 3: Client Bootstrap Protocol
- Implement
sync_with_peer_for_bootstrap()client method - Add bootstrap request submission to sync protocol
- Implement pending status handling
- Tests for client bootstrap flow
Phase 4: User Approval
- Implement
User::approve_bootstrap_request() - Implement
User::reject_bootstrap_request() - Add Admin permission checking and key addition logic
- Tests for approval workflow
Phase 5: Integration
- Update sync protocol to handle bootstrap responses
- Implement client retry logic
- End-to-end integration tests
- Documentation and examples
Future Enhancements
- Request Expiration: Automatically expire old pending requests
- Notification System: Notify users with Admin permission of new bootstrap requests
- Permission Negotiation: Allow approving user to grant different permission than requested
- Batch Approval: Approve multiple requests at once
- Bootstrap Policies: Configurable rules for auto-rejection (e.g., block certain addresses)
- Audit Log: Track all bootstrap requests and decisions
Conclusion
The bootstrap and access control system provides:
Wildcard Permissions:
- Simple open access for public databases
- Flexible permission levels (Read, Write, Admin)
- Per-database control
Bootstrap Protocol:
- Secure request/approval workflow
- User-controlled access grants
- Integration with Users system for authentication
Together, these mechanisms support both open and controlled access patterns for Eidetica databases.