Compare commits

...

3 Commits

Author SHA1 Message Date
Zoltan Papp
56d82a99e1 Backup and restore encryption key 2023-10-06 15:41:29 +02:00
Zoltan Papp
d25f543913 Handle idempotent way the encryption key 2023-10-06 14:37:24 +02:00
Zoltan Papp
672b4c0401 Eliminate repeated error messages
In case of encryption error fill variables
with content instead of empty string
2023-10-06 14:09:17 +02:00
7 changed files with 76 additions and 14 deletions

View File

@@ -170,6 +170,10 @@ if [ "$NETBIRD_DASH_AUTH_USE_AUDIENCE" = "false" ]; then
export NETBIRD_AUTH_PKCE_AUDIENCE=
fi
# Read the encryption key
encKey=$(grep DataStoreEncryptionKey management.json | awk -F'"' '{$0=$4}1')
export NETBIRD_DATASTORE_ENC_KEY=$encKey
env | grep NETBIRD
envsubst <docker-compose.yml.tmpl >docker-compose.yml

View File

@@ -27,6 +27,7 @@
"Password": null
},
"Datadir": "",
"DataStoreEncryptionKey": "$NETBIRD_DATASTORE_ENC_KEY",
"HttpConfig": {
"Address": "0.0.0.0:$NETBIRD_MGMT_API_PORT",
"AuthIssuer": "$NETBIRD_AUTH_AUTHORITY",

View File

@@ -301,15 +301,23 @@ var (
func initEventStore(dataDir string, key string) (activity.Store, string, error) {
var err error
if key == "" {
log.Debugf("generate new activity store encryption key")
key, err = sqlite.GenerateKey()
log.Debugf("restore or generate new activity store encryption key")
key, err = sqlite.RestoreKey(dataDir)
if err == nil {
goto CreateStore
} else {
log.Debugf("failed to restore encryption key for activity store: %s", err)
}
log.Infof("generate new encryption key for activity store")
key, err = sqlite.GenerateKey(dataDir)
if err != nil {
return nil, "", err
}
}
CreateStore:
store, err := sqlite.NewSQLiteStore(dataDir, key)
return store, key, err
}
func notifyStop(msg string) {

View File

@@ -7,6 +7,12 @@ import (
"crypto/rand"
"encoding/base64"
"fmt"
"os"
"path/filepath"
)
const (
backupFile = ".datastore.key"
)
var iv = []byte{10, 22, 13, 79, 05, 8, 52, 91, 87, 98, 88, 98, 35, 25, 13, 05}
@@ -15,16 +21,40 @@ type FieldEncrypt struct {
block cipher.Block
}
func GenerateKey() (string, error) {
func RestoreKey(dataDir string) (string, error) {
fName := filepath.Join(dataDir, backupFile)
data, err := os.ReadFile(fName)
return string(data), err
}
func GenerateKey(dataDir string) (string, error) {
key := make([]byte, 32)
_, err := rand.Read(key)
if err != nil {
return "", err
}
readableKey := base64.StdEncoding.EncodeToString(key)
err = saveKey(dataDir, readableKey)
if err != nil {
return "", err
}
return readableKey, nil
}
func saveKey(dataDir, key string) error {
f, err := os.Create(filepath.Join(dataDir, backupFile))
if err != nil {
return err
}
defer f.Close()
_, err = f.WriteString(key)
if err != nil {
return err
}
return nil
}
func NewFieldEncrypt(key string) (*FieldEncrypt, error) {
binKey, err := base64.StdEncoding.DecodeString(key)
if err != nil {

View File

@@ -2,11 +2,20 @@ package sqlite
import (
"testing"
log "github.com/sirupsen/logrus"
)
func TestRestoreKey(t *testing.T) {
_, err := RestoreKey(t.TempDir())
if err != nil {
log.Infof("err: %s", err)
}
}
func TestGenerateKey(t *testing.T) {
testData := "exampl@netbird.io"
key, err := GenerateKey()
key, err := GenerateKey(t.TempDir())
if err != nil {
t.Fatalf("failed to generate key: %s", err)
}
@@ -32,7 +41,7 @@ func TestGenerateKey(t *testing.T) {
func TestCorruptKey(t *testing.T) {
testData := "exampl@netbird.io"
key, err := GenerateKey()
key, err := GenerateKey(t.TempDir())
if err != nil {
t.Fatalf("failed to generate key: %s", err)
}
@@ -46,7 +55,7 @@ func TestCorruptKey(t *testing.T) {
t.Fatalf("invalid encrypted text")
}
newKey, err := GenerateKey()
newKey, err := GenerateKey(t.TempDir())
if err != nil {
t.Fatalf("failed to generate key: %s", err)
}

View File

@@ -45,6 +45,9 @@ const (
"VALUES(?, ?, ?, ?, ?, ?)"
insertDeleteUserQuery = `INSERT INTO deleted_users(id, email, name) VALUES(?, ?, ?)`
fallbackName = "unknown"
fallbackEmail = "unknown@unknown.com"
)
// Store is the implementation of the activity.Store interface backed by SQLite
@@ -128,6 +131,7 @@ func NewSQLiteStore(dataDir string, encryptionKey string) (*Store, error) {
func (store *Store) processResult(result *sql.Rows) ([]*activity.Event, error) {
events := make([]*activity.Event, 0)
var cryptErr error
for result.Next() {
var id int64
var operation activity.Activity
@@ -156,8 +160,8 @@ func (store *Store) processResult(result *sql.Rows) ([]*activity.Event, error) {
if targetUserName != nil {
name, err := store.fieldEncrypt.Decrypt(*targetUserName)
if err != nil {
log.Errorf("failed to decrypt username for target id: %s", target)
meta["username"] = ""
cryptErr = fmt.Errorf("failed to decrypt username for target id: %s", target)
meta["username"] = fallbackName
} else {
meta["username"] = name
}
@@ -166,8 +170,8 @@ func (store *Store) processResult(result *sql.Rows) ([]*activity.Event, error) {
if targetEmail != nil {
email, err := store.fieldEncrypt.Decrypt(*targetEmail)
if err != nil {
log.Errorf("failed to decrypt email address for target id: %s", target)
meta["email"] = ""
cryptErr = fmt.Errorf("failed to decrypt email address for target id: %s", target)
meta["email"] = fallbackEmail
} else {
meta["email"] = email
}
@@ -186,7 +190,8 @@ func (store *Store) processResult(result *sql.Rows) ([]*activity.Event, error) {
if initiatorName != nil {
name, err := store.fieldEncrypt.Decrypt(*initiatorName)
if err != nil {
log.Errorf("failed to decrypt username of initiator: %s", initiator)
cryptErr = fmt.Errorf("failed to decrypt username of initiator: %s", initiator)
event.InitiatorName = fallbackName
} else {
event.InitiatorName = name
}
@@ -195,7 +200,8 @@ func (store *Store) processResult(result *sql.Rows) ([]*activity.Event, error) {
if initiatorEmail != nil {
email, err := store.fieldEncrypt.Decrypt(*initiatorEmail)
if err != nil {
log.Errorf("failed to decrypt email address of initiator: %s", initiator)
cryptErr = fmt.Errorf("failed to decrypt email address of initiator: %s", initiator)
event.InitiatorEmail = fallbackEmail
} else {
event.InitiatorEmail = email
}
@@ -204,6 +210,10 @@ func (store *Store) processResult(result *sql.Rows) ([]*activity.Event, error) {
events = append(events, event)
}
if cryptErr != nil {
log.Warnf("%s", cryptErr)
}
return events, nil
}

View File

@@ -12,7 +12,7 @@ import (
func TestNewSQLiteStore(t *testing.T) {
dataDir := t.TempDir()
key, _ := GenerateKey()
key, _ := GenerateKey(dataDir)
store, err := NewSQLiteStore(dataDir, key)
if err != nil {
t.Fatal(err)