Enterprise-grade secret management without enterprise-grade complexity.
Your TYPO3 site integrates with Stripe, SendGrid, Google Maps, and a dozen other services. Where are those API keys right now?
Probably in plain text in LocalConfiguration.php, unencrypted in a database field, or hardcoded somewhere accessible to every backend user.
If your database leaks, your secrets leak. If you need to rotate a compromised key, you're editing config files and redeploying.
| Method | Security | Operational Reality |
|---|---|---|
| External Services (HashiCorp Vault, AWS SM) | βββββ | Infrastructure cost, network access, auth to service |
| Environment Variables | βββ | Deployment/host access required, restart to change, no rotation UI, no audit trail |
| Files outside webroot | βββ | Deployment/host access required, hard to rotate, no management interface |
| nr-vault (encrypted DB) | ββββ | Runtime manageable via TYPO3 backend, rotate anytime, full audit trail |
| Plain text in config/DB | β | β No protection |
All "more secure" methods require either external infrastructure, deployment pipelines, or server access. And they all lack a management UI and audit trail.
| Challenge | Env Vars / Files | nr-vault |
|---|---|---|
| Rotate a compromised API key | Call DevOps, redeploy, restart | Click in backend, done |
| See who accessed a secret | Check deploy logs (if any) | Full audit log with timestamps |
| Emergency credential revocation | Wait for deployment pipeline | Immediate via backend module |
| Non-technical editor updates SMTP password | Create support ticket | Self-service in backend |
| Compliance audit: prove access history | Manually correlate logs | Export tamper-evident audit trail |
nr-vault provides:
- Envelope encryption with AES-256-GCM via libsodium
- Master key management (file, environment variable, or derived)
- Per-secret access control via backend user groups with context scoping
- Audit logging of all secret access with tamper-evident hash chain
- Key rotation support for both secrets and master key
- TCA integration via custom
vaultSecretfield type - Vault HTTP Client - make authenticated API calls without exposing secrets
- CLI commands for DevOps automation
- Pluggable adapter architecture (external vault adapters planned for future releases)
flowchart TB
subgraph TYPO3["TYPO3 Backend"]
subgraph Entry["Entry Points"]
TCA["TCA Field<br/>(vaultSecret)"]
Backend["Backend Module<br/>(Secrets Manager)"]
CLI["CLI Commands"]
end
TCA & Backend & CLI --> VaultService
subgraph VaultService["VaultService"]
API["store() | retrieve() | rotate() | delete() | list() | http()"]
end
VaultService --> AccessControl["AccessControl<br/>Service"]
VaultService --> Encryption["EncryptionService"]
VaultService --> Audit["AuditLogService"]
Encryption --> Adapters
subgraph Adapters["Vault Adapters"]
Local["LocalDatabase<br/>(DEFAULT)"]
Future["Future: HashiCorp,<br/>AWS, Azure"]
end
end
Uses envelope encryption (same pattern as AWS KMS, Google Cloud KMS):
flowchart TB
MK["π Master Key<br/>(stored outside database)"]
DEK["π Data Encryption Key (DEK)<br/>(unique per secret)"]
Secret["π Secret Value<br/>(API key, password, token)"]
MK -->|encrypts| DEK
DEK -->|encrypts| Secret
Benefits:
- Master key rotation only requires re-encrypting DEKs (fast)
- Each secret has unique encryption
- Compromise of one secret doesn't expose others
use Netresearch\NrVault\Service\VaultServiceInterface;
class MyService
{
public function __construct(
private readonly VaultServiceInterface $vault,
) {}
public function storeApiKey(string $provider, string $apiKey): void
{
$this->vault->store(
identifier: "my_extension_{$provider}_api_key",
secret: $apiKey,
options: [
'owner' => $GLOBALS['BE_USER']->user['uid'],
'groups' => [1, 2], // Admin, Editor groups
'context' => 'payment', // Permission scoping
'expiresAt' => time() + 86400 * 90, // 90 days
]
);
}
public function getApiKey(string $provider): ?string
{
return $this->vault->retrieve("my_extension_{$provider}_api_key");
}
}Make authenticated API calls without exposing secrets to your code:
use Netresearch\NrVault\Http\SecretPlacement;
use Netresearch\NrVault\Http\VaultHttpClientInterface;
class PaymentService
{
public function __construct(
private readonly VaultHttpClientInterface $httpClient,
) {}
public function chargeCustomer(array $payload): array
{
// Secret is injected by vault - never visible to this code
$response = $this->httpClient->post(
'https://api.stripe.com/v1/charges',
[
'auth_secret' => 'stripe_api_key',
'placement' => SecretPlacement::Bearer,
'json' => $payload,
],
);
return json_decode($response->getBody()->getContents(), true);
}
}Secret placement options: Bearer, BasicAuth, Header, QueryParam, BodyField, ApiKey, OAuth2.
'api_key' => [
'label' => 'API Key',
'config' => [
'type' => 'input',
'renderType' => 'vaultSecret',
'size' => 30,
],
],# Initialize vault (create master key)
vendor/bin/typo3 vault:init
# List secrets (respects access control)
vendor/bin/typo3 vault:list
# Rotate a secret
vendor/bin/typo3 vault:rotate my_secret_id --reason="Scheduled rotation"
# Rotate master key (re-encrypts all DEKs)
vendor/bin/typo3 vault:rotate-master-key --new-key=/path/to/new.key --confirm
# View audit log
vendor/bin/typo3 vault:audit --identifier=my_secret_id --days=30
# Export secrets (encrypted backup)
vendor/bin/typo3 vault:export --output=secrets.enc- TYPO3: v14.0+
- PHP: ^8.5
- Extensions:
ext-sodium(bundled with PHP) - CPU: AES-NI support recommended (XChaCha20-Poly1305 fallback available)
Full documentation is available in the Documentation/ folder and can be rendered with the TYPO3 documentation tools.
docker run --rm -v $(pwd):/project ghcr.io/typo3-documentation/render-guides:latest --progress Documentation
# Open Documentation-GENERATED-temp/Index.htmlInternal development documents are available in docs/:
- Architecture - System architecture overview
- API Reference - Service API documentation
- Database Schema - Database structure
- Security Considerations - Security design decisions
- Use Cases - Supported use cases
| Feature | nr-vault | Drupal Key | Laravel Secrets | Symfony Secrets |
|---|---|---|---|---|
| Envelope encryption | Yes | No | No | No |
| Per-secret DEKs | Yes | No | No | No |
| External vault support | Planned | Pluggable | Limited | HashiCorp |
| Access control | BE groups + context | By key | N/A | N/A |
| Audit logging | Full + hash chain | Limited | None | None |
| TCA/Form integration | Native | Form API | N/A | N/A |
| Key rotation CLI | Yes | Manual | Yes | Yes |
| HTTP client | Yes | No | No | No |
| OAuth auto-refresh | Yes | No | No | No |
- Phase 1-5: Core functionality (current focus)
- Phase 6: External adapters (HashiCorp, AWS, Azure) + Optional Rust FFI for zero-PHP-exposure
- Phase 7: Service Registry - abstract away both credentials AND endpoints
composer require netresearch/nr-vaultOr in DDEV:
ddev start
ddev install-v14
ddev vault-initGPL-2.0-or-later
[n] Developed by Netresearch DTT GmbH - Enterprise TYPO3 Solutions