⭐ If you find this project useful, please consider giving it a star on GitHub! ⭐
gopgdekmanager
is a robust Go library for managing encryption keys in distributed environments using PostgreSQL. It provides a comprehensive system for handling Master Encryption Keys (MEKs) and Data Encryption Keys (DEKs), featuring automatic rotation, distributed locking, and recovery operations.
- Master Encryption Key (MEK) Management: Secure handling of MEKs, including rotation and recovery.
- Data Encryption Key (DEK) Management: Creation, retrieval, and rotation of DEKs for multiple named keys.
- Flexible DEK Generation: Supports multiple DEK generation functions (AES-128, AES-192, AES-256) with the ability to add custom functions.
- Key Registration: Separate key registration process, independent of MEK/DEK operations.
- Automatic DEK Rotation: Configurable periodic rotation of DEKs.
- Distributed Locking: Prevents race conditions in distributed environments during key operations.
- MEK Recovery: Support for recovery using older MEKs in emergency scenarios.
- Key Versioning: Maintains versions of both MEKs and DEKs for traceability and backward compatibility.
- PostgreSQL Backend: Utilizes PostgreSQL for secure storage of encrypted keys.
- Caching: In-memory caching of DEKs and key-function mappings for improved performance.
- Configurable Cleanup: Automatic cleanup of old, inactive keys after a configurable period.
go get github.com/tzahifadida/go-pg-dek-manager
import (
"context"
"database/sql"
"github.com/tzahifadida/go-pg-dek-manager"
)
db, err := sql.Open("postgres", "your_connection_string")
if err != nil {
// Handle error
}
mek := []byte("your-32-byte-master-encryption-key")
manager, err := gopgdekmanager.NewDEKManager(db, mek,
gopgdekmanager.WithCleanupPeriod(180*24*time.Hour),
gopgdekmanager.WithDEKRotationPeriod(30*24*time.Hour),
)
if err != nil {
// Handle error
}
defer manager.Shutdown()
ctx := context.Background()
err := manager.RegisterKey(ctx, "user_data")
if err != nil {
// Handle error
}
// To skip the key-function cache during registration:
err = manager.RegisterKey(ctx, "user_data", gopgdekmanager.WithSkipCache())
if err != nil {
// Handle error
}
dek, version, err := manager.GetDEK(ctx, "user_data")
if err != nil {
// Handle error
}
// Use dek for encryption/decryption
err := manager.RotateDEK(ctx, "user_data")
if err != nil {
// Handle error
}
dek, err := manager.GetDEKByVersion(ctx, "user_data", 2)
if err != nil {
// Handle error
}
// Use dek for decryption of data encrypted with this specific version
keys, err := manager.ListKeys(ctx)
if err != nil {
// Handle error
}
// keys is a slice of registered key names
genFuncName, latestVersion, err := manager.GetKeyInfo(ctx, "user_data")
if err != nil {
// Handle error
}
// genFuncName is the name of the generation function used for this key
// latestVersion is the latest version number of the DEK for this key
WithCleanupPeriod(d time.Duration)
: Set the period for cleaning up old DEKs.WithDEKRotationPeriod(d time.Duration)
: Set the period for automatic DEK rotation.WithTransitionCheckPeriod(d time.Duration)
: Set the period for checking MEK transitions.WithTablePrefix(prefix string)
: Set a custom table prefix for database tables.WithSchemaName(schema string)
: Set a custom schema name for database tables.WithLogger(logger MinimalLogger)
: Provide a custom logger implementation.WithLockLeaseDuration(d time.Duration)
: Set the duration for distributed locks.WithOldMEK(oldMEK []byte)
: Provide an old MEK for transition scenarios.WithMaxCacheSize(size int)
: Set the maximum size for the in-memory DEK cache.WithCacheExpiration(d time.Duration)
: Set the expiration duration for cached DEKs.WithDriverName(driverName string)
: Set the database driver name.WithFunction(name string, fn DEKGenerationFunc)
: Add a custom DEK generation function.WithDefaultGenFuncName(name string)
: Set the default DEK generation function name.WithMaxKeyFuncCache(size int)
: Set the maximum size for the key-function cache.WithSkipCache()
: Skip the key-function cache during key registration (use withRegisterKey
).
- The DEKManager caches the association between keys and their generation functions for improved performance.
- By default, key registration checks this cache before querying the database.
- Use
WithSkipCache()
when registering a key to bypass this cache and always check the database. - This can be useful in scenarios where you want to ensure the most up-to-date key information is used.
- Supports using older versions of MEKs with appropriate warnings.
- Allows DEK retrieval with old MEKs, but blocks rotation operations.
- Logs warnings when using an old MEK.
- MEK Security: Store the MEK securely outside of the database. Consider using a hardware security module (HSM) or secure key management service.
- Regular Rotation: Implement a policy for regular MEK and DEK rotation.
- Monitoring: Set up monitoring for key operations, especially failed attempts and recoveries.
- Backup: Regularly backup your database, including the key tables.
- Access Control: Implement strict access controls to the database and key management functions.
- Key Registration: Always register keys before attempting to get or rotate DEKs.
- Version Management: When encrypting data, store the DEK version along with the encrypted data to ensure correct decryption later.
- Cache Management: Use
WithSkipCache()
judiciously, typically in scenarios where you need to ensure the most recent key information is used.
- Uses distributed locking to prevent race conditions during key operations.
- Ensure all instances in your distributed system use the same database for consistency.
- Configure appropriate timeouts and retry mechanisms for distributed operations.
- This library provides key management functionality but does not handle the actual encryption of your data. Use the DEKs retrieved from this library with standard encryption libraries for data encryption.
- The default DEK generation function produces 32-byte (256-bit) keys, suitable for use with AES-256 and other strong symmetric encryption algorithms.
- Always use TLS for database connections in production environments.
- Regularly audit and rotate all keys, including database credentials.
- When using
GetDEKByVersion
, ensure that you're storing the DEK version along with your encrypted data to facilitate correct decryption.
The library includes a comprehensive test suite. To run the tests:
go test -v ./...
Note: The tests require Docker to be installed and running, as they use testcontainers-go to spin up a PostgreSQL instance.
Contributions to gopgdekmanager
are welcome! Please submit pull requests with any enhancements, bug fixes, or documentation improvements.
For issues, questions, or contributions, please open an issue in the GitHub repository.