Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion cmd/dependency/dependency.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ import (
"d7y.io/dragonfly/v2/pkg/types"
"d7y.io/dragonfly/v2/pkg/unit"
"d7y.io/dragonfly/v2/version"
manager_cfg "d7y.io/dragonfly/v2/manager/config"
)

// InitCommandAndConfig initializes flags binding and common sub cmds.
Expand Down Expand Up @@ -307,7 +308,8 @@ func initDecoderConfig(dc *mapstructure.DecoderConfig) {
reflect.TypeOf(config.URL{}),
reflect.TypeOf(net.IP{}),
reflect.TypeOf(config.CertPool{}),
reflect.TypeOf(config.Regexp{}):
reflect.TypeOf(config.Regexp{}),
reflect.TypeOf(manager_cfg.EncryptionKey{}):

b, _ := yaml.Marshal(v)
p := reflect.New(to)
Expand Down
44 changes: 44 additions & 0 deletions manager/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@
package config

import (
"encoding/base64"
"errors"
"fmt"
"net"
"time"

"d7y.io/dragonfly/v2/cmd/dependency/base"
logger "d7y.io/dragonfly/v2/internal/dflog"
"d7y.io/dragonfly/v2/pkg/net/ip"
"d7y.io/dragonfly/v2/pkg/objectstorage"
"d7y.io/dragonfly/v2/pkg/slices"
Expand Down Expand Up @@ -56,6 +58,9 @@ type Config struct {

// Network configuration.
Network NetworkConfig `yaml:"network" mapstructure:"network"`

// Encryption configuration
Encryption EncryptionConfig `yaml:"encryption" mapstructure:"encryption"`
}

type ServerConfig struct {
Expand Down Expand Up @@ -398,6 +403,36 @@ type NetworkConfig struct {
EnableIPv6 bool `mapstructure:"enableIPv6" yaml:"enableIPv6"`
}

// AES256 base64 key is 32 bytes.
type EncryptionKey [32]byte
type EncryptionConfig struct {
// Enable encryption.
Enable bool `mapstructure:"enable" yaml:"enable"`
// AES256 base64, optional
Key *EncryptionKey `mapstructure:"key" yaml:"key"`
}

// UnmarshalText Base64
func (e *EncryptionKey) UnmarshalText(text []byte) error {
logger.Debugf("base64 key str: %s", string(text))
keyBytes, err := base64.StdEncoding.DecodeString(string(text))
if err != nil {
return fmt.Errorf("invalid base64 key: %v", err)
}

if len(keyBytes) != 32 {
return fmt.Errorf("key must be 32 bytes, got %d", len(keyBytes))
}

copy(e[:], keyBytes)
return nil
}

// MarshalText Base64
func (e EncryptionKey) MarshalText() ([]byte, error) {
return []byte(base64.StdEncoding.EncodeToString(e[:])), nil
}

// New config instance.
func New() *Config {
return &Config{
Expand Down Expand Up @@ -489,6 +524,9 @@ func New() *Config {
Network: NetworkConfig{
EnableIPv6: DefaultNetworkEnableIPv6,
},
Encryption: EncryptionConfig{
Enable: false,
},
}
}

Expand Down Expand Up @@ -686,6 +724,12 @@ func (cfg *Config) Validate() error {
}
}

if cfg.Encryption.Enable {
if cfg.Encryption.Key == nil {
return errors.New("encryption requires parameter key")
}
}

return nil
}

Expand Down
1 change: 1 addition & 0 deletions manager/database/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ func migrate(db *gorm.DB) error {
&models.Application{},
&models.PersonalAccessToken{},
&models.Peer{},
&models.EncryptionKey{},
)
}

Expand Down
44 changes: 44 additions & 0 deletions manager/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@ package manager

import (
"context"
"crypto/rand"
"embed"
"encoding/base64"
"encoding/hex"
"errors"
"fmt"
"io/fs"
"net"
Expand All @@ -37,6 +41,7 @@ import (
managergc "d7y.io/dragonfly/v2/manager/gc"
"d7y.io/dragonfly/v2/manager/job"
"d7y.io/dragonfly/v2/manager/metrics"
"d7y.io/dragonfly/v2/manager/models"
"d7y.io/dragonfly/v2/manager/permission/rbac"
"d7y.io/dragonfly/v2/manager/router"
"d7y.io/dragonfly/v2/manager/rpcserver"
Expand Down Expand Up @@ -122,6 +127,16 @@ func New(cfg *config.Config, d dfpath.Dfpath) (*Server, error) {
return nil, err
}

// Initialize encryption key
if cfg.Encryption.Enable {
if err := initializeEncryptionKey(cfg, db.DB); err != nil {
return nil, err
}
logger.Infof("encryption enabled")
} else {
logger.Infof("encryption disabled")
}

// Initialize enforcer.
enforcer, err := rbac.NewEnforcer(db.DB)
if err != nil {
Expand Down Expand Up @@ -250,6 +265,35 @@ func registerGCTasks(gc pkggc.GC, db *gorm.DB) error {
return nil
}

// Initialize encryption key
func initializeEncryptionKey(cfg *config.Config, db *gorm.DB) error {
// 1. try get key from db
var existingKey models.EncryptionKey
if err := db.First(&existingKey).Error; err == nil {
logger.Infof("encryption key loaded from database, key(hex): %s, key(base64): %s",
hex.EncodeToString(existingKey.Key),
base64.StdEncoding.EncodeToString(existingKey.Key),
)
} else if !errors.Is(err, gorm.ErrRecordNotFound) {
return fmt.Errorf("failed to check encryption key: %v", err)
}

// 2. if there is no key in db, generate a new one
keyBytes := make([]byte, 32)
if _, err := rand.Read(keyBytes); err != nil {
return fmt.Errorf("failed to generate random encryption key: %v", err)
}
if err := db.Create(&models.EncryptionKey{Key: keyBytes}).Error; err != nil {
return fmt.Errorf("failed to save random encryption key to database: %v", err)
}
logger.Infof(
"generated random encryption key and saved to database, key(hex): %s, key(base64): %s",
hex.EncodeToString(keyBytes),
base64.StdEncoding.EncodeToString(keyBytes),
)
return nil
}

// Serve starts the manager server.
func (s *Server) Serve() error {
// Started REST server.
Expand Down
6 changes: 6 additions & 0 deletions manager/models/encryption.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package models

type EncryptionKey struct {
BaseModel
Key []byte `gorm:"type:binary(32);not null;unique" json:"key"`
}
21 changes: 21 additions & 0 deletions manager/rpcserver/manager_server_v2.go
Original file line number Diff line number Diff line change
Expand Up @@ -976,3 +976,24 @@ func (s *managerServerV2) KeepAlive(stream managerv2.Manager_KeepAliveServer) er
}
}
}

// RequestEncryptionKey implements manager.ManagerServer.
func (s *managerServerV2) RequestEncryptionKey(ctx context.Context, req *managerv2.RequestEncryptionKeyRequest) (*managerv2.RequestEncryptionKeyResponse, error) {
log := logger.WithHostnameAndIP(req.Hostname, req.Ip)
if !s.config.Encryption.Enable {
return &managerv2.RequestEncryptionKeyResponse{
Status: managerv2.EncryptionStatus_ENCRYPTION_DISABLED,
}, nil
}
// Get key from db
var encKey models.EncryptionKey
if err := s.db.WithContext(ctx).First(&encKey).Error; err != nil {
log.Errorf("failed to get encryption key: %v", err)
return nil, status.Error(codes.Internal, "failed to get encryption key")
}

return &managerv2.RequestEncryptionKeyResponse{
Status: managerv2.EncryptionStatus_ENCRYPTION_ENABLED,
EncryptionKey: encKey.Key,
}, nil
}