mirror of
https://github.com/fleetdm/fleet
synced 2026-05-23 08:58:41 +00:00
fix: move encryption to ds
This commit is contained in:
parent
3d4e196048
commit
cd2b254c6f
4 changed files with 71 additions and 59 deletions
|
|
@ -3,10 +3,14 @@ package mysql
|
|||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
|
@ -4117,6 +4121,50 @@ VALUES
|
|||
return nil
|
||||
}
|
||||
|
||||
func encrypt(plainText []byte, privateKey string) ([]byte, error) {
|
||||
block, err := aes.NewCipher([]byte(privateKey))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create new cipher: %w", err)
|
||||
}
|
||||
|
||||
aesGCM, err := cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create new gcm: %w", err)
|
||||
}
|
||||
|
||||
nonce := make([]byte, aesGCM.NonceSize())
|
||||
if _, err = io.ReadFull(rand.Reader, nonce); err != nil {
|
||||
return nil, fmt.Errorf("generate nonce: %w", err)
|
||||
}
|
||||
|
||||
return aesGCM.Seal(nonce, nonce, plainText, nil), nil
|
||||
}
|
||||
|
||||
func decrypt(encrypted []byte, privateKey string) ([]byte, error) {
|
||||
block, err := aes.NewCipher([]byte(privateKey))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create new cipher: %w", err)
|
||||
}
|
||||
|
||||
aesGCM, err := cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create new gcm: %w", err)
|
||||
}
|
||||
|
||||
// Get the nonce size
|
||||
nonceSize := aesGCM.NonceSize()
|
||||
|
||||
// Extract the nonce from the encrypted data
|
||||
nonce, ciphertext := encrypted[:nonceSize], encrypted[nonceSize:]
|
||||
|
||||
decrypted, err := aesGCM.Open(nil, nonce, ciphertext, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("generate nonce: %w", err)
|
||||
}
|
||||
|
||||
return decrypted, nil
|
||||
}
|
||||
|
||||
func (ds *Datastore) InsertMDMConfigAssets(ctx context.Context, assets []fleet.MDMConfigAsset) error {
|
||||
stmt := `
|
||||
INSERT INTO
|
||||
|
|
@ -4132,8 +4180,12 @@ VALUES
|
|||
var insertVals strings.Builder
|
||||
|
||||
for _, a := range assets {
|
||||
encryptedVal, err := encrypt(a.Value, ds.serverPrivateKey)
|
||||
if err != nil {
|
||||
return ctxerr.Wrap(ctx, err, fmt.Sprintf("encrypting mdm config asset %s", a.Name))
|
||||
}
|
||||
insertVals.WriteString(`(?, ?),`)
|
||||
args = append(args, a.Name, a.Value)
|
||||
args = append(args, a.Name, encryptedVal)
|
||||
}
|
||||
|
||||
stmt = fmt.Sprintf(stmt, strings.TrimSuffix(insertVals.String(), ","))
|
||||
|
|
@ -4167,6 +4219,15 @@ WHERE
|
|||
return nil, ctxerr.Wrap(ctx, err, "get mdm config assets by name")
|
||||
}
|
||||
|
||||
for i, a := range res {
|
||||
decryptedVal, err := decrypt(a.Value, ds.serverPrivateKey)
|
||||
if err != nil {
|
||||
return nil, ctxerr.Wrap(ctx, err, fmt.Sprintf("decrypting mdm config asset %s", a.Name))
|
||||
}
|
||||
|
||||
res[i].Value = decryptedVal
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ type dbOptions struct {
|
|||
tracingConfig *config.LoggingConfig
|
||||
minLastOpenedAtDiff time.Duration
|
||||
sqlMode string
|
||||
privateKey string
|
||||
}
|
||||
|
||||
// Logger adds a logger to the datastore.
|
||||
|
|
@ -73,6 +74,7 @@ func TracingEnabled(lconfig *config.LoggingConfig) DBOption {
|
|||
func WithFleetConfig(conf *config.FleetConfig) DBOption {
|
||||
return func(o *dbOptions) error {
|
||||
o.minLastOpenedAtDiff = conf.Osquery.MinSoftwareLastOpenedAtDiff
|
||||
o.privateKey = conf.Server.PrivateKey
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,6 +104,10 @@ type Datastore struct {
|
|||
//
|
||||
// e.g.: testBatchSetMDMWindowsProfilesErr = "insert:fail"
|
||||
testBatchSetMDMWindowsProfilesErr string
|
||||
|
||||
// This key is used to encrypt sensitive data stored in the Fleet DB, for example MDM
|
||||
// certificates and keys.
|
||||
serverPrivateKey string
|
||||
}
|
||||
|
||||
// reader returns the DB instance to use for read-only statements, which is the
|
||||
|
|
@ -335,6 +339,7 @@ func New(config config.MysqlConfig, c clock.Clock, opts ...DBOption) (*Datastore
|
|||
writeCh: make(chan itemToWrite),
|
||||
stmtCache: make(map[string]*sqlx.Stmt),
|
||||
minLastOpenedAtDiff: options.minLastOpenedAtDiff,
|
||||
serverPrivateKey: options.privateKey,
|
||||
}
|
||||
|
||||
go ds.writeChanLoop()
|
||||
|
|
|
|||
|
|
@ -3,9 +3,6 @@ package service
|
|||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
|
|
@ -2121,50 +2118,6 @@ func (svc *Service) ResendHostMDMProfile(ctx context.Context, hostID uint, profi
|
|||
// GET /mdm/apple/request_csr
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
func Encrypt(plainText []byte, privateKey string) ([]byte, error) {
|
||||
block, err := aes.NewCipher([]byte(privateKey))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create new cipher: %w", err)
|
||||
}
|
||||
|
||||
aesGCM, err := cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create new gcm: %w", err)
|
||||
}
|
||||
|
||||
nonce := make([]byte, aesGCM.NonceSize())
|
||||
if _, err = io.ReadFull(rand.Reader, nonce); err != nil {
|
||||
return nil, fmt.Errorf("generate nonce: %w", err)
|
||||
}
|
||||
|
||||
return aesGCM.Seal(nonce, nonce, plainText, nil), nil
|
||||
}
|
||||
|
||||
func Decrypt(encrypted []byte, privateKey string) ([]byte, error) {
|
||||
block, err := aes.NewCipher([]byte(privateKey))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create new cipher: %w", err)
|
||||
}
|
||||
|
||||
aesGCM, err := cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create new gcm: %w", err)
|
||||
}
|
||||
|
||||
// Get the nonce size
|
||||
nonceSize := aesGCM.NonceSize()
|
||||
|
||||
// Extract the nonce from the encrypted data
|
||||
nonce, ciphertext := encrypted[:nonceSize], encrypted[nonceSize:]
|
||||
|
||||
decrypted, err := aesGCM.Open(nil, nonce, ciphertext, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("generate nonce: %w", err)
|
||||
}
|
||||
|
||||
return decrypted, nil
|
||||
}
|
||||
|
||||
type getMDMAppleCSRRequest struct{}
|
||||
|
||||
type getMDMAppleCSRResponse struct {
|
||||
|
|
@ -2224,13 +2177,9 @@ func (svc *Service) GetMDMAppleCSR(ctx context.Context) ([]byte, error) {
|
|||
fleet.MDMAssetCAKey: apple_mdm.EncodePrivateKeyPEM(scepKey),
|
||||
fleet.MDMAssetAPNSKey: apple_mdm.EncodePrivateKeyPEM(apnsKey),
|
||||
} {
|
||||
encryptedVal, err := Encrypt(v, svc.config.Server.PrivateKey)
|
||||
if err != nil {
|
||||
return nil, ctxerr.Wrap(ctx, err, fmt.Sprintf("encrypting mdm config asset %s", k))
|
||||
}
|
||||
assets = append(assets, fleet.MDMConfigAsset{
|
||||
Name: k,
|
||||
Value: encryptedVal,
|
||||
Value: v,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -2240,12 +2189,7 @@ func (svc *Service) GetMDMAppleCSR(ctx context.Context) ([]byte, error) {
|
|||
} else {
|
||||
for _, a := range savedAssets {
|
||||
if a.Name == fleet.MDMAssetAPNSKey {
|
||||
// decrypt value first
|
||||
decryptedKey, err := Decrypt(a.Value, svc.config.Server.PrivateKey)
|
||||
if err != nil {
|
||||
return nil, ctxerr.Wrap(ctx, err, "decrypting apns key")
|
||||
}
|
||||
block, _ := pem.Decode(decryptedKey)
|
||||
block, _ := pem.Decode(a.Value)
|
||||
if block == nil {
|
||||
return nil, ctxerr.Wrap(ctx, errors.New("decoding apns key"))
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue