fix: move encryption to ds

This commit is contained in:
Jahziel Villasana-Espinoza 2024-05-28 11:31:17 -04:00
parent 3d4e196048
commit cd2b254c6f
4 changed files with 71 additions and 59 deletions

View file

@ -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
}

View file

@ -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
}
}

View file

@ -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()

View file

@ -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"))
}