Key Stores
Tayra uses a pluggable key store architecture to persist encryption keys. Every key store implements the IKeyStore interface, giving you freedom to choose the backend that best fits your infrastructure.
Available Providers
| Provider | Package | Use Case | Persistence | Encryption at Rest |
|---|---|---|---|---|
| In-Memory | Tayra.Core (built-in) | Unit tests, throwaway demos | No | No |
| SQLite | Tayra.KeyStore.Sqlite | Local development (zero-config) | Yes | No (raw key bytes) |
| PostgreSQL | Tayra.KeyStore.PostgreSql | Local dev or self-managed production | Yes | No (requires hardening) |
| HashiCorp Vault | Tayra.KeyStore.Vault | Production | Yes | Yes (seal) |
| Azure Key Vault | Tayra.KeyStore.AzureKeyVault | Production | Yes | Yes (HSM-backed) |
| AWS Parameter Store | Tayra.KeyStore.AwsParameterStore | Production | Yes | Yes (KMS) |
| AWS Secrets Manager | Tayra.KeyStore.AwsSecretsManager | Production (per-tenant) | Yes | Yes (KMS) |
| AWS Aurora (IAM auth) | Tayra.KeyStore.AwsAurora | Production (AWS-native PG) | Yes | No (requires hardening) |
Choosing a Key Store
| Environment | Recommended Provider | Why |
|---|---|---|
| Unit/integration tests | In-Memory | Zero configuration, no external dependencies |
| Local development | SQLite | Zero-config file-based persistence, no server needed |
| Local development (with PG) | PostgreSQL | Persistent keys, useful if you already run PostgreSQL locally |
| Self-managed production | PostgreSQL (with hardening) | For teams that don't use cloud secrets managers |
| Production on AWS Aurora | AWS Aurora (IAM auth) | PostgreSQL compatibility with ephemeral IAM DB auth tokens |
| Production | Vault, Azure Key Vault, or AWS KMS | HSM-backed encryption, access auditing, key wrapping |
SQLite - Development Only (in either role)
The SQLite key store stores raw key bytes without envelope encryption. It is for local development only - including when used as the master keystore via .WithSqliteMasterKey(...). Production deployments must use a hardened secrets manager regardless of role.
AWS Secrets Manager - Per-Secret Pricing
Secrets Manager bills $0.40 per secret per month. With Tayra's default per-data-subject key model, a customer base of 100k users costs ~$40k/month. Use AWS Parameter Store for per-subject keys; use Secrets Manager only for per-tenant key models or when policy mandates it.
PostgreSQL - Requires Hardening for Production
The PostgreSQL key store stores raw key bytes in a database table. It can be used in production only with proper hardening (TDE, TLS, pgAudit, least-privilege access). See the Production Security Guide for the full checklist. Without hardening, use it for development only.
The IKeyStore Interface
All key stores implement IKeyStore, which defines these operations:
public interface IKeyStore
{
Task StoreAsync(string keyId, byte[] key, CancellationToken ct = default);
Task<byte[]?> GetAsync(string keyId, CancellationToken ct = default);
Task DeleteAsync(string keyId, CancellationToken ct = default);
Task<bool> ExistsAsync(string keyId, CancellationToken ct = default);
Task DeleteByPrefixAsync(string prefix, CancellationToken ct = default);
Task<IReadOnlyList<string>> ListKeyIdsAsync(string prefix, CancellationToken ct = default);
Task<IReadOnlyList<KeyInfo>> GetKeysCreatedBeforeAsync(
DateTimeOffset cutoff, int limit = 100, CancellationToken ct = default);
}- StoreAsync - Stores a key. Implementations should be idempotent (no-op if the key already exists).
- GetAsync - Retrieves a key by ID. Returns
nullif the key has been deleted (crypto-shredded). - DeleteAsync - Deletes a key. This is the crypto-shredding operation.
- ExistsAsync - Checks whether a key exists without retrieving its value.
- DeleteByPrefixAsync - Bulk crypto-shredding by key prefix (e.g., delete all keys for a data subject).
- ListKeyIdsAsync - Lists key IDs matching a prefix. Used for key rotation discovery.
- GetKeysCreatedBeforeAsync - Finds keys older than a cutoff time. Used for data retention policies.
INFO
ListKeyIdsAsync and GetKeysCreatedBeforeAsync have default implementations that throw NotSupportedException. Not all providers support these operations.
Fail-Closed on Key-Store Errors
If the key store cannot be reached while resolving a key - a connectivity issue, bad credentials, or a missing schema/table - encryption and decryption fail closed: Tayra raises a TayraKeyStoreUnavailableException (with the underlying store error as its InnerException) rather than persisting unprotected data or letting a raw, non-attributable store error surface downstream. Because key resolution runs before any field is encrypted, the exception is raised with your object unmodified, so no half-encrypted or corrupt data reaches your database.
try
{
await session.SaveChangesAsync();
}
catch (TayraKeyStoreUnavailableException ex)
{
// ex.KeyId, ex.Operation ("load" / "store" / "list"), and ex.InnerException
// point at the real cause (e.g. the key-store schema does not exist).
}Registration Pattern
Every key store follows the same chained registration pattern. Call services.AddTayra() to register core services and chain the provider-specific Use* method:
var services = new ServiceCollection();
services.AddTayra(opts => opts.LicenseKey = licenseKey);You can also build a custom key store if none of the built-in providers fit your needs.
See Also
- Installation - NuGet package installation for all providers
- Custom Key Store - Implementing your own
IKeyStore
