Skip to content

Commit 244a56d

Browse files
FEATURE (secrets): Move secrets to the secret.key file instead of DB
1 parent 95c833b commit 244a56d

File tree

18 files changed

+144
-86
lines changed

18 files changed

+144
-86
lines changed

backend/cmd/main.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
backups_config "postgresus-backend/internal/features/backups/config"
1919
"postgresus-backend/internal/features/databases"
2020
"postgresus-backend/internal/features/disk"
21+
"postgresus-backend/internal/features/encryption/secrets"
2122
healthcheck_attempt "postgresus-backend/internal/features/healthcheck/attempt"
2223
healthcheck_config "postgresus-backend/internal/features/healthcheck/config"
2324
"postgresus-backend/internal/features/notifiers"
@@ -64,6 +65,12 @@ func main() {
6465
os.Exit(1)
6566
}
6667

68+
err = secrets.GetSecretKeyService().MigrateKeyFromDbToFileIfExist()
69+
if err != nil {
70+
log.Error("Failed to migrate secret key from database to file", "error", err)
71+
os.Exit(1)
72+
}
73+
6774
err = users_services.GetUserService().CreateInitialAdmin()
6875
if err != nil {
6976
log.Error("Failed to create initial admin", "error", err)

backend/internal/config/config.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,9 @@ type EnvVariables struct {
2626
EnvMode env_utils.EnvMode `env:"ENV_MODE" required:"true"`
2727
PostgresesInstallDir string `env:"POSTGRES_INSTALL_DIR"`
2828

29-
DataFolder string
30-
TempFolder string
29+
DataFolder string
30+
TempFolder string
31+
SecretKeyPath string
3132

3233
TestGoogleDriveClientID string `env:"TEST_GOOGLE_DRIVE_CLIENT_ID"`
3334
TestGoogleDriveClientSecret string `env:"TEST_GOOGLE_DRIVE_CLIENT_SECRET"`
@@ -146,6 +147,7 @@ func loadEnvVariables() {
146147
// (projectRoot/postgresus-data -> /postgresus-data)
147148
env.DataFolder = filepath.Join(filepath.Dir(backendRoot), "postgresus-data", "backups")
148149
env.TempFolder = filepath.Join(filepath.Dir(backendRoot), "postgresus-data", "temp")
150+
env.SecretKeyPath = filepath.Join(filepath.Dir(backendRoot), "postgresus-data", "secret.key")
149151

150152
if env.IsTesting {
151153
if env.TestPostgres12Port == "" {

backend/internal/features/backups/backups/di.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
package backups
22

33
import (
4+
"time"
5+
46
audit_logs "postgresus-backend/internal/features/audit_logs"
57
"postgresus-backend/internal/features/backups/backups/usecases"
68
backups_config "postgresus-backend/internal/features/backups/config"
79
"postgresus-backend/internal/features/databases"
10+
encryption_secrets "postgresus-backend/internal/features/encryption/secrets"
811
"postgresus-backend/internal/features/notifiers"
912
"postgresus-backend/internal/features/storages"
10-
users_repositories "postgresus-backend/internal/features/users/repositories"
1113
workspaces_services "postgresus-backend/internal/features/workspaces/services"
1214
"postgresus-backend/internal/util/encryption"
1315
"postgresus-backend/internal/util/logger"
14-
"time"
1516
)
1617

1718
var backupRepository = &BackupRepository{}
@@ -25,7 +26,7 @@ var backupService = &BackupService{
2526
notifiers.GetNotifierService(),
2627
notifiers.GetNotifierService(),
2728
backups_config.GetBackupConfigService(),
28-
users_repositories.GetSecretKeyRepository(),
29+
encryption_secrets.GetSecretKeyService(),
2930
encryption.GetFieldEncryptor(),
3031
usecases.GetCreateBackupUsecase(),
3132
logger.GetLogger(),

backend/internal/features/backups/backups/service.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,20 @@ import (
77
"fmt"
88
"io"
99
"log/slog"
10+
"slices"
11+
"strings"
12+
"time"
13+
1014
audit_logs "postgresus-backend/internal/features/audit_logs"
1115
"postgresus-backend/internal/features/backups/backups/encryption"
1216
backups_config "postgresus-backend/internal/features/backups/config"
1317
"postgresus-backend/internal/features/databases"
18+
encryption_secrets "postgresus-backend/internal/features/encryption/secrets"
1419
"postgresus-backend/internal/features/notifiers"
1520
"postgresus-backend/internal/features/storages"
1621
users_models "postgresus-backend/internal/features/users/models"
17-
users_repositories "postgresus-backend/internal/features/users/repositories"
1822
workspaces_services "postgresus-backend/internal/features/workspaces/services"
1923
util_encryption "postgresus-backend/internal/util/encryption"
20-
"slices"
21-
"strings"
22-
"time"
2324

2425
"github.com/google/uuid"
2526
)
@@ -31,7 +32,7 @@ type BackupService struct {
3132
notifierService *notifiers.NotifierService
3233
notificationSender NotificationSender
3334
backupConfigService *backups_config.BackupConfigService
34-
secretKeyRepo *users_repositories.SecretKeyRepository
35+
secretKeyService *encryption_secrets.SecretKeyService
3536
fieldEncryptor util_encryption.FieldEncryptor
3637

3738
createBackupUseCase CreateBackupUsecase
@@ -628,7 +629,7 @@ func (s *BackupService) getBackupReader(backupID uuid.UUID) (io.ReadCloser, erro
628629
}
629630

630631
// Get master key
631-
masterKey, err := s.secretKeyRepo.GetSecretKey()
632+
masterKey, err := s.secretKeyService.GetSecretKey()
632633
if err != nil {
633634
if closeErr := fileReader.Close(); closeErr != nil {
634635
s.logger.Error("Failed to close file reader", "error", closeErr)

backend/internal/features/backups/backups/service_test.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,22 @@ package backups
33
import (
44
"context"
55
"errors"
6+
"strings"
7+
"testing"
8+
"time"
9+
610
usecases_postgresql "postgresus-backend/internal/features/backups/backups/usecases/postgresql"
711
backups_config "postgresus-backend/internal/features/backups/config"
812
"postgresus-backend/internal/features/databases"
13+
encryption_secrets "postgresus-backend/internal/features/encryption/secrets"
914
"postgresus-backend/internal/features/notifiers"
1015
"postgresus-backend/internal/features/storages"
1116
users_enums "postgresus-backend/internal/features/users/enums"
12-
users_repositories "postgresus-backend/internal/features/users/repositories"
1317
users_testing "postgresus-backend/internal/features/users/testing"
1418
workspaces_services "postgresus-backend/internal/features/workspaces/services"
1519
workspaces_testing "postgresus-backend/internal/features/workspaces/testing"
1620
"postgresus-backend/internal/util/encryption"
1721
"postgresus-backend/internal/util/logger"
18-
"strings"
19-
"testing"
20-
"time"
2122

2223
"github.com/google/uuid"
2324
"github.com/stretchr/testify/assert"
@@ -56,7 +57,7 @@ func Test_BackupExecuted_NotificationSent(t *testing.T) {
5657
notifiers.GetNotifierService(),
5758
mockNotificationSender,
5859
backups_config.GetBackupConfigService(),
59-
users_repositories.GetSecretKeyRepository(),
60+
encryption_secrets.GetSecretKeyService(),
6061
encryption.GetFieldEncryptor(),
6162
&CreateFailedBackupUsecase{},
6263
logger.GetLogger(),
@@ -104,7 +105,7 @@ func Test_BackupExecuted_NotificationSent(t *testing.T) {
104105
notifiers.GetNotifierService(),
105106
mockNotificationSender,
106107
backups_config.GetBackupConfigService(),
107-
users_repositories.GetSecretKeyRepository(),
108+
encryption_secrets.GetSecretKeyService(),
108109
encryption.GetFieldEncryptor(),
109110
&CreateSuccessBackupUsecase{},
110111
logger.GetLogger(),
@@ -129,7 +130,7 @@ func Test_BackupExecuted_NotificationSent(t *testing.T) {
129130
notifiers.GetNotifierService(),
130131
mockNotificationSender,
131132
backups_config.GetBackupConfigService(),
132-
users_repositories.GetSecretKeyRepository(),
133+
encryption_secrets.GetSecretKeyService(),
133134
encryption.GetFieldEncryptor(),
134135
&CreateSuccessBackupUsecase{},
135136
logger.GetLogger(),

backend/internal/features/backups/backups/usecases/postgresql/create_backup_uc.go

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ import (
1919
backups_config "postgresus-backend/internal/features/backups/config"
2020
"postgresus-backend/internal/features/databases"
2121
pgtypes "postgresus-backend/internal/features/databases/databases/postgresql"
22+
encryption_secrets "postgresus-backend/internal/features/encryption/secrets"
2223
"postgresus-backend/internal/features/storages"
23-
users_repositories "postgresus-backend/internal/features/users/repositories"
2424
"postgresus-backend/internal/util/encryption"
2525
"postgresus-backend/internal/util/tools"
2626

@@ -34,16 +34,15 @@ const (
3434
progressReportIntervalMB = 1.0
3535
pgConnectTimeout = 30
3636
compressionLevel = 5
37-
defaultBackupLimit = 1000
3837
exitCodeAccessViolation = -1073741819
3938
exitCodeGenericError = 1
4039
exitCodeConnectionError = 2
4140
)
4241

4342
type CreatePostgresqlBackupUsecase struct {
44-
logger *slog.Logger
45-
secretKeyRepo *users_repositories.SecretKeyRepository
46-
fieldEncryptor encryption.FieldEncryptor
43+
logger *slog.Logger
44+
secretKeyService *encryption_secrets.SecretKeyService
45+
fieldEncryptor encryption.FieldEncryptor
4746
}
4847

4948
// Execute creates a backup of the database
@@ -466,7 +465,7 @@ func (uc *CreatePostgresqlBackupUsecase) setupBackupEncryption(
466465
return nil, nil, metadata, fmt.Errorf("failed to generate nonce: %w", err)
467466
}
468467

469-
masterKey, err := uc.secretKeyRepo.GetSecretKey()
468+
masterKey, err := uc.secretKeyService.GetSecretKey()
470469
if err != nil {
471470
return nil, nil, metadata, fmt.Errorf("failed to get master key: %w", err)
472471
}

backend/internal/features/backups/backups/usecases/postgresql/di.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
package usecases_postgresql
22

33
import (
4-
users_repositories "postgresus-backend/internal/features/users/repositories"
4+
"postgresus-backend/internal/features/encryption/secrets"
55
"postgresus-backend/internal/util/encryption"
66
"postgresus-backend/internal/util/logger"
77
)
88

99
var createPostgresqlBackupUsecase = &CreatePostgresqlBackupUsecase{
1010
logger.GetLogger(),
11-
users_repositories.GetSecretKeyRepository(),
11+
secrets.GetSecretKeyService(),
1212
encryption.GetFieldEncryptor(),
1313
}
1414

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package secrets
2+
3+
var secretKeyService = &SecretKeyService{
4+
nil,
5+
}
6+
7+
func GetSecretKeyService() *SecretKeyService {
8+
return secretKeyService
9+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
package secrets
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package secrets
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"os"
7+
8+
"postgresus-backend/internal/config"
9+
user_models "postgresus-backend/internal/features/users/models"
10+
"postgresus-backend/internal/storage"
11+
12+
"github.com/google/uuid"
13+
"gorm.io/gorm"
14+
)
15+
16+
type SecretKeyService struct {
17+
cachedKey *string
18+
}
19+
20+
func (s *SecretKeyService) MigrateKeyFromDbToFileIfExist() error {
21+
var secretKey user_models.SecretKey
22+
23+
err := storage.GetDb().First(&secretKey).Error
24+
if err != nil {
25+
if errors.Is(err, gorm.ErrRecordNotFound) {
26+
return nil
27+
}
28+
return fmt.Errorf("failed to check for secret key in database: %w", err)
29+
}
30+
31+
if secretKey.Secret == "" {
32+
return nil
33+
}
34+
35+
secretKeyPath := config.GetEnv().SecretKeyPath
36+
if err := os.WriteFile(secretKeyPath, []byte(secretKey.Secret), 0600); err != nil {
37+
return fmt.Errorf("failed to write secret key to file: %w", err)
38+
}
39+
40+
if err := storage.GetDb().Exec("DELETE FROM secret_keys").Error; err != nil {
41+
return fmt.Errorf("failed to delete secret key from database: %w", err)
42+
}
43+
44+
return nil
45+
}
46+
47+
func (s *SecretKeyService) GetSecretKey() (string, error) {
48+
if s.cachedKey != nil {
49+
return *s.cachedKey, nil
50+
}
51+
52+
secretKeyPath := config.GetEnv().SecretKeyPath
53+
data, err := os.ReadFile(secretKeyPath)
54+
if err != nil {
55+
if os.IsNotExist(err) {
56+
newKey := s.generateNewSecretKey()
57+
if err := os.WriteFile(secretKeyPath, []byte(newKey), 0600); err != nil {
58+
return "", fmt.Errorf("failed to write new secret key: %w", err)
59+
}
60+
s.cachedKey = &newKey
61+
return newKey, nil
62+
}
63+
return "", fmt.Errorf("failed to read secret key file: %w", err)
64+
}
65+
66+
key := string(data)
67+
s.cachedKey = &key
68+
return key, nil
69+
}
70+
71+
func (s *SecretKeyService) generateNewSecretKey() string {
72+
return uuid.New().String() + uuid.New().String()
73+
}

0 commit comments

Comments
 (0)