396 lines
8.7 KiB
Markdown
396 lines
8.7 KiB
Markdown
# Mount Point Detection and Multi-Mount Search
|
|
|
|
## Overview
|
|
|
|
The application now automatically detects all available KV secret engine mount points when you log in, and allows you to search across all of them simultaneously.
|
|
|
|
## How It Works
|
|
|
|
### 1. Login Verification
|
|
|
|
When you log in, the application:
|
|
|
|
1. **Verifies your credentials** by calling `/v1/sys/internal/ui/mounts`
|
|
2. **Discovers all mount points** available on the Vault server
|
|
3. **Filters for KV secret engines** (type: `kv` or `generic`)
|
|
4. **Detects KV versions** automatically from mount options
|
|
5. **Stores mount points** in the connection state
|
|
|
|
```typescript
|
|
// Example mount points detected:
|
|
[
|
|
{ path: "secret", type: "kv", options: { version: "2" } },
|
|
{ path: "cubbyhole", type: "cubbyhole", options: {} },
|
|
{ path: "identity", type: "identity", options: {} },
|
|
{ path: "sys", type: "system", options: {} }
|
|
]
|
|
|
|
// Filtered to KV engines only:
|
|
[
|
|
{ path: "secret", type: "kv", options: { version: "2" } }
|
|
]
|
|
```
|
|
|
|
### 2. Search Modes
|
|
|
|
The application supports two search modes:
|
|
|
|
#### Mode 1: Single Base Path (Default)
|
|
- ✅ Search within a specific mount point/path
|
|
- ✅ Fast and targeted
|
|
- ✅ Use when you know where to look
|
|
|
|
```typescript
|
|
// Search only in secret/myapp/
|
|
Base Path: secret/myapp/
|
|
Search Term: database
|
|
```
|
|
|
|
#### Mode 2: All Mount Points
|
|
- ✅ Search across all detected KV mount points
|
|
- ✅ Comprehensive coverage
|
|
- ✅ Use when you don't know which mount contains the secret
|
|
- ⚠️ Slower (searches multiple mount points sequentially)
|
|
|
|
```typescript
|
|
// Searches: secret/, secret-v1/, team-secrets/, etc.
|
|
☑ Search across all mount points (3 available)
|
|
Search Term: database
|
|
```
|
|
|
|
## UI Features
|
|
|
|
### Login Process
|
|
|
|
**Before (without verification):**
|
|
```
|
|
1. Enter credentials
|
|
2. Click "Connect"
|
|
3. Hope it works 🤞
|
|
```
|
|
|
|
**After (with verification):**
|
|
```
|
|
1. Enter credentials
|
|
2. Click "Connect"
|
|
3. ✓ Login verified via API call
|
|
4. ✓ Mount points detected
|
|
5. ✓ "Found 3 KV mount point(s)" message
|
|
6. If login fails: detailed error message
|
|
```
|
|
|
|
### Search Interface
|
|
|
|
**Checkbox:** "Search across all mount points"
|
|
- Shows number of available mounts: "(3 available)"
|
|
- Disabled if no mount points detected
|
|
- Off by default (single path search)
|
|
|
|
**When Enabled:**
|
|
- Base Path field hidden (not needed)
|
|
- Searches all detected KV mount points
|
|
- Results show mount point indicator: 📌
|
|
|
|
**When Disabled:**
|
|
- Base Path field visible
|
|
- Normal single-path search behavior
|
|
|
|
### Search Results
|
|
|
|
**With Single Path Search:**
|
|
```
|
|
📄 secret/myapp/database/credentials
|
|
Depth: 2
|
|
```
|
|
|
|
**With All Mounts Search:**
|
|
```
|
|
📄 secret/myapp/database/credentials
|
|
📌 secret
|
|
Depth: 2
|
|
|
|
📄 team-secrets/shared/database
|
|
📌 team-secrets
|
|
Depth: 1
|
|
```
|
|
|
|
## Technical Implementation
|
|
|
|
### API Call: `/v1/sys/internal/ui/mounts`
|
|
|
|
**Request:**
|
|
```http
|
|
GET /v1/sys/internal/ui/mounts HTTP/1.1
|
|
Host: vault.example.com
|
|
X-Vault-Token: your-token
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"data": {
|
|
"secret/": {
|
|
"type": "kv",
|
|
"description": "key/value secret storage",
|
|
"accessor": "kv_abc123",
|
|
"config": {
|
|
"default_lease_ttl": 0,
|
|
"max_lease_ttl": 0
|
|
},
|
|
"options": {
|
|
"version": "2"
|
|
}
|
|
},
|
|
"cubbyhole/": {
|
|
"type": "cubbyhole",
|
|
"description": "per-token private secret storage",
|
|
...
|
|
},
|
|
...
|
|
}
|
|
}
|
|
```
|
|
|
|
### Mount Point Filtering
|
|
|
|
Only KV secret engines are included:
|
|
- `type === 'kv'` - KV v1 or v2
|
|
- `type === 'generic'` - Legacy KV v1
|
|
|
|
Other types are excluded:
|
|
- `cubbyhole` - Per-token storage (not searchable)
|
|
- `identity` - Identity management
|
|
- `system` - System backend
|
|
- `pki` - PKI certificates
|
|
- `aws`, `azure`, `gcp` - Dynamic secrets
|
|
- etc.
|
|
|
|
### KV Version Detection
|
|
|
|
```typescript
|
|
// From mount options
|
|
const kvVersion = mount.options?.version === '2' ? 2 : 1;
|
|
|
|
// Automatically used for path transformation
|
|
// KV v2: secret/ → secret/metadata/ for LIST
|
|
// KV v1: secret/ → secret/ as-is
|
|
```
|
|
|
|
### Search Algorithm
|
|
|
|
**Single Path:**
|
|
```
|
|
1. Search in base path
|
|
2. Recurse into subdirectories
|
|
3. Return results
|
|
```
|
|
|
|
**All Mounts:**
|
|
```
|
|
1. For each KV mount point:
|
|
a. Detect KV version
|
|
b. Search from mount root
|
|
c. Recurse into subdirectories
|
|
d. Add results with mount indicator
|
|
e. Check max results limit
|
|
2. Combine all results
|
|
3. Return aggregated results
|
|
```
|
|
|
|
## Performance Considerations
|
|
|
|
### Caching Strategy
|
|
|
|
**All searches are cached:**
|
|
- Single path search: Cached per path
|
|
- All mounts search: Each mount path cached separately
|
|
- Cache key includes mount point
|
|
- Repeated searches are instant
|
|
|
|
**Cache Benefits:**
|
|
- Prevents redundant API calls
|
|
- Faster subsequent searches
|
|
- Respects DDoS prevention limits
|
|
|
|
### Search Limits
|
|
|
|
**Applied globally across all mounts:**
|
|
```typescript
|
|
config.search.maxResults = 1000; // Total across all mounts
|
|
config.search.maxDepth = 10; // Per mount point
|
|
|
|
// Example:
|
|
// Mount 1: 400 results, depth 8 ✓
|
|
// Mount 2: 300 results, depth 7 ✓
|
|
// Mount 3: 300 results, depth 5 ✓
|
|
// Total: 1000 results - stops here
|
|
```
|
|
|
|
### Performance Tips
|
|
|
|
1. **Use single path search** when you know the mount
|
|
2. **Enable all mounts search** for discovery
|
|
3. **Adjust max results** in settings if needed
|
|
4. **Use specific search terms** to limit results
|
|
5. **Check console** for per-mount progress
|
|
|
|
## Error Handling
|
|
|
|
### Login Verification Fails
|
|
|
|
```
|
|
Error: Login verification failed: permission denied
|
|
|
|
Possible causes:
|
|
1. Invalid credentials
|
|
2. Token expired
|
|
3. No permission to list mounts
|
|
4. Network/CORS issues
|
|
|
|
Solution: Check credentials and permissions
|
|
```
|
|
|
|
### Mount Point Access Denied
|
|
|
|
```
|
|
✓ Found 3 KV mount point(s): secret, secret-v1, team-secrets
|
|
→ Searching in secret/
|
|
✓ 45 results
|
|
→ Searching in secret-v1/
|
|
✗ Error: permission denied
|
|
→ Searching in team-secrets/
|
|
✓ 23 results
|
|
|
|
✓ Found 68 total result(s) across all mounts
|
|
```
|
|
|
|
**Behavior:**
|
|
- Continues with other mounts
|
|
- Logs error for failed mount
|
|
- Returns partial results
|
|
- User sees console warning
|
|
|
|
## Use Cases
|
|
|
|
### Use Case 1: Discovery
|
|
|
|
**Scenario:** "I know there's a database credential somewhere, but I don't remember which mount."
|
|
|
|
**Solution:**
|
|
```
|
|
1. ☑ Enable "Search across all mount points"
|
|
2. Search Term: "database"
|
|
3. Get results from all mounts:
|
|
- secret/prod/database
|
|
- secret/dev/database
|
|
- team-secrets/shared/database
|
|
```
|
|
|
|
### Use Case 2: Specific Search
|
|
|
|
**Scenario:** "I need to find all Redis configs in the production secrets."
|
|
|
|
**Solution:**
|
|
```
|
|
1. ☐ Disable "Search across all mount points"
|
|
2. Base Path: secret/prod/
|
|
3. Search Term: "redis"
|
|
4. Fast, targeted results
|
|
```
|
|
|
|
### Use Case 3: Multi-Team Environment
|
|
|
|
**Scenario:** Multiple teams with separate mount points
|
|
|
|
**Detected mounts:**
|
|
```
|
|
- secret (shared)
|
|
- team-a-secrets
|
|
- team-b-secrets
|
|
- team-c-secrets
|
|
```
|
|
|
|
**All mounts search:**
|
|
- Finds secrets across all team mounts
|
|
- Shows which mount each result is in
|
|
- Respects permissions (skips unauthorized mounts)
|
|
|
|
## Console Output Examples
|
|
|
|
### Login:
|
|
```
|
|
⚡ Verifying login and fetching mount points...
|
|
✓ Found 3 KV mount point(s): ["secret", "secret-v1", "team-secrets"]
|
|
✓ Logged in successfully. Found 3 KV mount point(s).
|
|
```
|
|
|
|
### Single Path Search:
|
|
```
|
|
⚡ API call for list: secret/myapp/
|
|
✓ Cache hit for list: secret/myapp/database/
|
|
🔍 Searching...
|
|
✓ Found 12 result(s) in 0.45s
|
|
```
|
|
|
|
### All Mounts Search:
|
|
```
|
|
🔍 Searching across 3 mount point(s)...
|
|
→ Searching in secret/
|
|
✓ 45 results from secret
|
|
→ Searching in secret-v1/
|
|
✓ 23 results from secret-v1
|
|
→ Searching in team-secrets/
|
|
✗ Error searching team-secrets: permission denied
|
|
✓ Found 68 total result(s) across all mounts
|
|
```
|
|
|
|
## Security Implications
|
|
|
|
### What's Exposed
|
|
|
|
**Mount point names and structure:**
|
|
- ✅ Visible to anyone who can log in
|
|
- ✅ No secret data exposed
|
|
- ✅ Only KV mounts shown
|
|
- ✅ Respects Vault ACLs
|
|
|
|
### Permissions
|
|
|
|
**Required permissions:**
|
|
```hcl
|
|
# To list mounts (login verification)
|
|
path "sys/internal/ui/mounts" {
|
|
capabilities = ["read"]
|
|
}
|
|
|
|
# To search in a mount
|
|
path "secret/metadata/*" { # KV v2
|
|
capabilities = ["list"]
|
|
}
|
|
|
|
path "secret/*" { # KV v1
|
|
capabilities = ["list"]
|
|
}
|
|
```
|
|
|
|
### Failed Permission Handling
|
|
|
|
- ✅ Graceful degradation
|
|
- ✅ Continues with accessible mounts
|
|
- ✅ Logs denied mounts
|
|
- ✅ No error thrown to user
|
|
|
|
## Summary
|
|
|
|
✅ **Login now verifies credentials** via API call
|
|
✅ **Mount points auto-detected** on login
|
|
✅ **Search across all mounts** optional feature (off by default)
|
|
✅ **Mount indicator** in search results
|
|
✅ **Automatic KV version detection** per mount
|
|
✅ **Graceful error handling** for inaccessible mounts
|
|
✅ **Performance optimized** with caching
|
|
✅ **Security conscious** - respects Vault ACLs
|
|
|
|
This feature makes it much easier to discover secrets across large Vault deployments with multiple mount points!
|
|
|