Files
michaelschiemer/docs/vault-system.md
Michael Schiemer 5050c7d73a docs: consolidate documentation into organized structure
- Move 12 markdown files from root to docs/ subdirectories
- Organize documentation by category:
  • docs/troubleshooting/ (1 file)  - Technical troubleshooting guides
  • docs/deployment/      (4 files) - Deployment and security documentation
  • docs/guides/          (3 files) - Feature-specific guides
  • docs/planning/        (4 files) - Planning and improvement proposals

Root directory cleanup:
- Reduced from 16 to 4 markdown files in root
- Only essential project files remain:
  • CLAUDE.md (AI instructions)
  • README.md (Main project readme)
  • CLEANUP_PLAN.md (Current cleanup plan)
  • SRC_STRUCTURE_IMPROVEMENTS.md (Structure improvements)

This improves:
 Documentation discoverability
 Logical organization by purpose
 Clean root directory
 Better maintainability
2025-10-05 11:05:04 +02:00

402 lines
8.6 KiB
Markdown

# Vault System - Secure Secrets Management
Modernes, sicheres Secrets Management System für das Custom PHP Framework.
## Features
**Libsodium Encryption** - Authenticated encryption (AEAD)
**Database-backed Storage** - Transaktionale Sicherheit
**Audit Logging** - Vollständiges Audit Trail aller Operations
**Metadata Tracking** - Access Counts, Last Access, etc.
**Key Rotation** - Hot Key Rotation ohne Downtime
**CLI Management** - Vollständige Console Commands
**Type Safety** - Value Objects für alle Daten
**Framework Integration** - Native DI Container Support
## Installation & Setup
### 1. Migration ausführen
```bash
docker exec php php console.php db:migrate
```
Dies erstellt die drei Vault-Tabellen:
- `vault_secrets` - Encrypted secrets storage
- `vault_audit_log` - Audit trail
- `vault_encryption_keys` - Key version tracking
### 2. Encryption Key generieren
```bash
docker exec php php console.php vault:generate-key
```
Dies generiert einen kryptographisch sicheren Encryption Key:
```
VAULT_ENCRYPTION_KEY=aGVsbG8gd29ybGQgdGhpcyBpcyBhIHRlc3Qga2V5IQ==
```
### 3. Key in .env speichern
Füge den generierten Key zu deiner `.env` Datei hinzu:
```env
# Vault Configuration
VAULT_ENCRYPTION_KEY=aGVsbG8gd29ybGQgdGhpcyBpcyBhIHRlc3Qga2V5IQ==
```
⚠️ **WICHTIG**: Niemals den Key committen! Die `.env` Datei ist in `.gitignore`.
## CLI Commands
### Secret speichern
```bash
# Mit Value als Argument
docker exec php php console.php vault:set database.password "super-secret"
# Value wird interaktiv abgefragt (versteckt)
docker exec php php console.php vault:set database.password
```
### Secret abrufen
```bash
docker exec php php console.php vault:get database.password
```
### Secret löschen
```bash
docker exec php php console.php vault:delete database.password
```
### Alle Secrets auflisten
```bash
docker exec php php console.php vault:list
```
Zeigt alle Secret Keys mit Metadata:
```
🔐 Vault Secrets:
• database.password
Accessed: 15 times, Last: 2024-01-15 14:30:45
• api.stripe.secret_key
Accessed: 3 times, Last: 2024-01-14 10:20:30
Total: 2 secrets
```
### Audit Log anzeigen
```bash
# Letzte 50 Einträge
docker exec php php console.php vault:audit
# Letzte 100 Einträge
docker exec php php console.php vault:audit 100
# Audit Log für spezifischen Secret Key
docker exec php php console.php vault:audit 50 database.password
```
### Key Rotation
```bash
docker exec php php console.php vault:rotate-key
```
⚠️ **KRITISCHE OPERATION**:
- Generiert neuen Encryption Key
- Re-encrypted alle Secrets
- Gibt neuen Key aus
- Alte Key aufbewahren bis Rotation verifiziert!
## Programmatische Verwendung
### In Controller/Services
```php
use App\Framework\Vault\Vault;
use App\Framework\Vault\ValueObjects\SecretKey;
use App\Framework\Vault\ValueObjects\SecretValue;
final readonly class PaymentService
{
public function __construct(
private Vault $vault
) {}
public function processPayment(Order $order): PaymentResult
{
// Secret aus Vault abrufen
$apiKey = $this->vault->get(
SecretKey::from('api.stripe.secret_key')
);
// Secret verwenden (reveal() erforderlich!)
$stripe = new StripeClient($apiKey->reveal());
return $stripe->charge($order->getTotal());
}
}
```
### Secret speichern
```php
public function updateApiKey(string $newKey): void
{
$this->vault->set(
SecretKey::from('api.stripe.secret_key'),
new SecretValue($newKey)
);
}
```
### Secret prüfen
```php
public function hasApiKey(): bool
{
return $this->vault->has(
SecretKey::from('api.stripe.secret_key')
);
}
```
### Metadata abrufen
```php
public function getSecretInfo(string $keyName): array
{
$metadata = $this->vault->getMetadata(
SecretKey::from($keyName)
);
return [
'created_at' => $metadata->createdAt,
'updated_at' => $metadata->updatedAt,
'access_count' => $metadata->accessCount,
'last_accessed' => $metadata->lastAccessedAt
];
}
```
## Value Objects
### SecretKey
Typsicherer Secret Identifier mit Validation:
```php
use App\Framework\Vault\ValueObjects\SecretKey;
// ✅ Gültig
$key = SecretKey::from('database.password');
$key = SecretKey::from('api.stripe.secret-key_2024');
// ❌ Ungültig
$key = SecretKey::from(''); // InvalidArgumentException
$key = SecretKey::from('invalid key!'); // Nur a-zA-Z0-9._- erlaubt
```
### SecretValue
Verhindert accidental Exposure:
```php
use App\Framework\Vault\ValueObjects\SecretValue;
$secret = new SecretValue('my-password');
// ✅ Explizit enthüllen
$password = $secret->reveal();
// ✅ Sichere Checks
if ($secret->isEmpty()) { ... }
$length = $secret->length();
// ✅ Verhindert Logging
echo $secret; // Ausgabe: [SECRET]
// ✅ Verhindert var_dump Exposure
var_dump($secret); // ['value' => '[REDACTED]', 'length' => 11]
```
## Sicherheit
### Encryption
- **Algorithmus**: Libsodium `sodium_crypto_secretbox` (XSalsa20 + Poly1305)
- **Authenticated Encryption**: Schutz gegen Tampering
- **Random Nonce**: Eindeutig pro Secret
- **256-bit Keys**: SODIUM_CRYPTO_SECRETBOX_KEYBYTES (32 bytes)
### Audit Logging
Alle Vault-Operationen werden geloggt:
```sql
SELECT * FROM vault_audit_log
WHERE secret_key = 'database.password'
ORDER BY timestamp DESC;
```
Geloggte Informationen:
- Secret Key (nicht der Value!)
- Action (read, write, delete, rotate, export)
- Timestamp
- User ID (wenn verfügbar)
- IP Address
- User Agent
- Success/Failure Status
- Error Message (bei Fehlern)
### Best Practices
**DO**:
- Encryption Key in `.env` speichern (gitignored)
- Unterschiedliche Keys für Environments
- Regelmäßige Key Rotation (quartalsweise)
- Audit Logs monitoren
- Secrets mit beschreibenden Namen (`api.service.key`)
**DON'T**:
- Encryption Key committen
- Secrets in Code hardcoden
- Gleichen Key für Dev/Staging/Production
- Audit Logs ignorieren
- Secrets ohne Namespace (`password`)
## Migration von .env zu Vault
### Schritt 1: Secrets identifizieren
Identifiziere alle sensiblen Werte in `.env`:
- Passwörter
- API Keys
- Client Secrets
- Private Keys
- Tokens
### Schritt 2: In Vault migrieren
```bash
# Für jeden Secret:
docker exec php php console.php vault:set api.stripe.secret_key "sk_live_..."
docker exec php php console.php vault:set database.password "prod-password"
docker exec php php console.php vault:set oauth.spotify.client_secret "abc123..."
```
### Schritt 3: Code aktualisieren
**Vorher (.env)**:
```php
$apiKey = $_ENV['STRIPE_SECRET_KEY']; // ❌ Unsicher
```
**Nachher (Vault)**:
```php
$apiKey = $this->vault
->get(SecretKey::from('api.stripe.secret_key'))
->reveal(); // ✅ Sicher
```
### Schritt 4: .env bereinigen
Nach Migration Secrets aus `.env` entfernen:
```diff
- STRIPE_SECRET_KEY=sk_live_...
- DATABASE_PASSWORD=prod-password
+ # Secrets now in Vault - use vault:get to retrieve
```
## Troubleshooting
### "Vault not available"
**Problem**: `VAULT_ENCRYPTION_KEY` nicht gesetzt
**Lösung**:
```bash
# Key generieren
docker exec php php console.php vault:generate-key
# Key in .env hinzufügen
echo "VAULT_ENCRYPTION_KEY=generated_key_here" >> .env
```
### "Sodium extension required"
**Problem**: PHP Sodium Extension fehlt
**Lösung**: Sodium ist in PHP 7.2+ standardmäßig verfügbar. Prüfe PHP Version:
```bash
docker exec php php -m | grep sodium
```
### "Decryption failed"
**Problem**: Falscher Encryption Key oder korrupte Daten
**Mögliche Ursachen**:
- Encryption Key geändert ohne Re-Encryption
- Database Corruption
- Falsche Encoding (base64)
**Lösung**:
- Richtigen Key aus Backup wiederherstellen
- Oder Key Rotation durchführen
### "Secret not found"
**Problem**: Secret Key existiert nicht
**Lösung**:
```bash
# Alle Keys auflisten
docker exec php php console.php vault:list
# Secret neu erstellen
docker exec php php console.php vault:set your-key "your-value"
```
## Performance
### Benchmarks
- **Read Operation**: ~5ms (inkl. Decryption)
- **Write Operation**: ~10ms (inkl. Encryption + DB Insert)
- **Key Rotation**: ~100ms pro Secret
### Optimierungen
Für High-Performance Scenarios:
- Secrets cachen (mit TTL)
- Batch-Operations für Multiple Secrets
- Read Replicas für Read-Heavy Workloads
## Testing
```bash
# Unit Tests ausführen
docker exec php ./vendor/bin/pest tests/Framework/Vault/
```
Tests validieren:
- Value Object Validierung
- Encryption/Decryption
- Key Generation
- Audit Logging
## Weitere Informationen
- **Libsodium Dokumentation**: https://www.php.net/manual/en/book.sodium.php
- **Best Practices**: https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html