Skip to content

Commit 53ab74f

Browse files
committed
GODRIVER-3289 Add option to configure DEK cache lifetime.
1 parent 0b2f755 commit 53ab74f

File tree

13 files changed

+708
-59
lines changed

13 files changed

+708
-59
lines changed

etc/install-libmongocrypt.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# This script installs libmongocrypt into an "install" directory.
44
set -eux
55

6-
LIBMONGOCRYPT_TAG="1.11.0"
6+
LIBMONGOCRYPT_TAG="1.12.0"
77

88
# Install libmongocrypt based on OS.
99
if [ "Windows_NT" = "${OS:-}" ]; then

internal/integration/json_helpers_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,8 @@ func createAutoEncryptionOptions(t testing.TB, opts bson.Raw) *options.AutoEncry
162162
aeo.SetEncryptedFieldsMap(encryptedFieldsMap)
163163
case "bypassQueryAnalysis":
164164
aeo.SetBypassQueryAnalysis(opt.Boolean())
165+
case "keyExpirationMS":
166+
aeo.SetKeyExpiration(time.Duration(opt.Int64()) * time.Millisecond)
165167
default:
166168
t.Fatalf("unrecognized auto encryption option: %v", name)
167169
}

internal/integration/unified/entity.go

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ type clientEncryptionOpts struct {
179179
KeyVaultClient string `bson:"keyVaultClient"`
180180
KeyVaultNamespace string `bson:"keyVaultNamespace"`
181181
KmsProviders map[string]bson.Raw `bson:"kmsProviders"`
182+
keyExpirationMS *int64 `bson:"keyExpirationMS"`
182183
}
183184

184185
// EntityMap is used to store entities during tests. This type enforces uniqueness so no two entities can have the same
@@ -735,12 +736,15 @@ func (em *EntityMap) addClientEncryptionEntity(entityOptions *entityOptions) err
735736
return newEntityNotFoundError("client", ceo.KeyVaultClient)
736737
}
737738

738-
ce, err := mongo.NewClientEncryption(
739-
keyVaultClient.Client,
740-
options.ClientEncryption().
741-
SetKeyVaultNamespace(ceo.KeyVaultNamespace).
742-
SetTLSConfig(tlsconf).
743-
SetKmsProviders(kmsProviders))
739+
opts := options.ClientEncryption().
740+
SetKeyVaultNamespace(ceo.KeyVaultNamespace).
741+
SetTLSConfig(tlsconf).
742+
SetKmsProviders(kmsProviders)
743+
if ceo.keyExpirationMS != nil {
744+
opts.SetKeyExpiration(time.Duration(*ceo.keyExpirationMS) * time.Millisecond)
745+
}
746+
747+
ce, err := mongo.NewClientEncryption(keyVaultClient.Client, opts)
744748
if err != nil {
745749
return err
746750
}

mongo/client.go

Lines changed: 30 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ func newClient(opts ...*options.ClientOptions) (*Client, error) {
193193
}
194194
// AutoEncryptionOptions
195195
if clientOpts.AutoEncryptionOptions != nil {
196-
if err := client.configureAutoEncryption(clientOpts); err != nil {
196+
if err = client.configureAutoEncryption(clientOpts); err != nil {
197197
return nil, err
198198
}
199199
} else {
@@ -471,30 +471,48 @@ func (c *Client) endSessions(ctx context.Context) {
471471
}
472472

473473
func (c *Client) configureAutoEncryption(args *options.ClientOptions) error {
474-
c.encryptedFieldsMap = args.AutoEncryptionOptions.EncryptedFieldsMap
474+
aeOpts := args.AutoEncryptionOptions
475+
c.encryptedFieldsMap = aeOpts.EncryptedFieldsMap
475476
if err := c.configureKeyVaultClientFLE(args); err != nil {
476477
return err
477478
}
478479

479-
if err := c.configureMetadataClientFLE(args); err != nil {
480-
return err
481-
}
482-
483-
mc, err := c.newMongoCrypt(args.AutoEncryptionOptions)
480+
mc, err := c.newMongoCrypt(aeOpts)
484481
if err != nil {
485482
return err
486483
}
487484

488485
// If the crypt_shared library was not loaded, try to spawn and connect to mongocryptd.
489486
if mc.CryptSharedLibVersionString() == "" {
490-
mongocryptdFLE, err := newMongocryptdClient(args.AutoEncryptionOptions)
487+
c.mongocryptdFLE, err = newMongocryptdClient(aeOpts)
491488
if err != nil {
492489
return err
493490
}
494-
c.mongocryptdFLE = mongocryptdFLE
495491
}
496492

497-
c.configureCryptFLE(mc, args.AutoEncryptionOptions)
493+
kr := keyRetriever{coll: c.keyVaultCollFLE}
494+
var cir collInfoRetriever
495+
bypass := aeOpts.BypassAutoEncryption != nil && *aeOpts.BypassAutoEncryption
496+
if !bypass {
497+
if args.MaxPoolSize != nil && *args.MaxPoolSize == 0 {
498+
c.metadataClientFLE = c
499+
} else {
500+
c.metadataClientFLE, err = c.getOrCreateInternalClient(args)
501+
if err != nil {
502+
return err
503+
}
504+
}
505+
cir.client = c.metadataClientFLE
506+
}
507+
508+
c.cryptFLE = driver.NewCrypt(&driver.CryptOptions{
509+
MongoCrypt: mc,
510+
CollInfoFn: cir.cryptCollInfo,
511+
KeyFn: kr.cryptKeys,
512+
MarkFn: c.mongocryptdFLE.markCommand,
513+
TLSConfig: aeOpts.TLSConfig,
514+
BypassAutoEncryption: bypass,
515+
})
498516
return nil
499517
}
500518

@@ -537,24 +555,6 @@ func (c *Client) configureKeyVaultClientFLE(clientOpts *options.ClientOptions) e
537555
return nil
538556
}
539557

540-
func (c *Client) configureMetadataClientFLE(clientOpts *options.ClientOptions) error {
541-
aeOpts := clientOpts.AutoEncryptionOptions
542-
543-
if aeOpts.BypassAutoEncryption != nil && *aeOpts.BypassAutoEncryption {
544-
// no need for a metadata client.
545-
return nil
546-
}
547-
if clientOpts.MaxPoolSize != nil && *clientOpts.MaxPoolSize == 0 {
548-
c.metadataClientFLE = c
549-
return nil
550-
}
551-
552-
var err error
553-
c.metadataClientFLE, err = c.getOrCreateInternalClient(clientOpts)
554-
555-
return err
556-
}
557-
558558
func (c *Client) newMongoCrypt(opts *options.AutoEncryptionOptions) (*mongocrypt.MongoCrypt, error) {
559559
// convert schemas in SchemaMap to bsoncore documents
560560
cryptSchemaMap := make(map[string]bsoncore.Document)
@@ -611,7 +611,8 @@ func (c *Client) newMongoCrypt(opts *options.AutoEncryptionOptions) (*mongocrypt
611611
SetEncryptedFieldsMap(cryptEncryptedFieldsMap).
612612
SetCryptSharedLibDisabled(cryptSharedLibDisabled || bypassAutoEncryption).
613613
SetCryptSharedLibOverridePath(cryptSharedLibPath).
614-
SetHTTPClient(opts.HTTPClient))
614+
SetHTTPClient(opts.HTTPClient).
615+
SetKeyExpiration(opts.KeyExpiration))
615616
if err != nil {
616617
return nil, err
617618
}
@@ -637,28 +638,6 @@ func (c *Client) newMongoCrypt(opts *options.AutoEncryptionOptions) (*mongocrypt
637638
return mc, nil
638639
}
639640

640-
//nolint:unused // the unused linter thinks that this function is unreachable because "c.newMongoCrypt" always panics without the "cse" build tag set.
641-
func (c *Client) configureCryptFLE(mc *mongocrypt.MongoCrypt, opts *options.AutoEncryptionOptions) {
642-
bypass := opts.BypassAutoEncryption != nil && *opts.BypassAutoEncryption
643-
kr := keyRetriever{coll: c.keyVaultCollFLE}
644-
var cir collInfoRetriever
645-
// If bypass is true, c.metadataClientFLE is nil and the collInfoRetriever
646-
// will not be used. If bypass is false, to the parent client or the
647-
// internal client.
648-
if !bypass {
649-
cir = collInfoRetriever{client: c.metadataClientFLE}
650-
}
651-
652-
c.cryptFLE = driver.NewCrypt(&driver.CryptOptions{
653-
MongoCrypt: mc,
654-
CollInfoFn: cir.cryptCollInfo,
655-
KeyFn: kr.cryptKeys,
656-
MarkFn: c.mongocryptdFLE.markCommand,
657-
TLSConfig: opts.TLSConfig,
658-
BypassAutoEncryption: bypass,
659-
})
660-
}
661-
662641
// validSession returns an error if the session doesn't belong to the client
663642
func (c *Client) validSession(sess *session.Client) error {
664643
if sess != nil && sess.ClientID != c.id {

mongo/client_encryption.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ func NewClientEncryption(keyVaultClient *Client, opts ...options.Lister[options.
5959
// ClientEncryption because it's only needed for AutoEncryption and we don't expect users to
6060
// have the crypt_shared library installed if they're using ClientEncryption.
6161
SetCryptSharedLibDisabled(true).
62-
SetHTTPClient(cea.HTTPClient))
62+
SetHTTPClient(cea.HTTPClient).
63+
SetKeyExpiration(cea.KeyExpiration))
6364
if err != nil {
6465
return nil, err
6566
}

mongo/options/autoencryptionoptions.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ package options
99
import (
1010
"crypto/tls"
1111
"net/http"
12+
"time"
1213

1314
"go.mongodb.org/mongo-driver/v2/internal/httputil"
1415
)
@@ -40,6 +41,7 @@ type AutoEncryptionOptions struct {
4041
HTTPClient *http.Client
4142
EncryptedFieldsMap map[string]interface{}
4243
BypassQueryAnalysis *bool
44+
KeyExpiration *time.Duration
4345
}
4446

4547
// AutoEncryption creates a new AutoEncryptionOptions configured with default values.
@@ -164,3 +166,10 @@ func (a *AutoEncryptionOptions) SetBypassQueryAnalysis(bypass bool) *AutoEncrypt
164166

165167
return a
166168
}
169+
170+
// SetKeyExpiration specifies duration for the key expiration. 0 means "never expire".
171+
func (a *AutoEncryptionOptions) SetKeyExpiration(expiration time.Duration) *AutoEncryptionOptions {
172+
a.KeyExpiration = &expiration
173+
174+
return a
175+
}

mongo/options/clientencryptionoptions.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"crypto/tls"
1111
"fmt"
1212
"net/http"
13+
"time"
1314

1415
"go.mongodb.org/mongo-driver/v2/internal/httputil"
1516
)
@@ -22,6 +23,7 @@ type ClientEncryptionOptions struct {
2223
KmsProviders map[string]map[string]interface{}
2324
TLSConfig map[string]*tls.Config
2425
HTTPClient *http.Client
26+
KeyExpiration *time.Duration
2527
}
2628

2729
// ClientEncryptionOptionsBuilder contains options to configure client
@@ -80,6 +82,17 @@ func (c *ClientEncryptionOptionsBuilder) SetTLSConfig(cfg map[string]*tls.Config
8082
return c
8183
}
8284

85+
// SetKeyExpiration specifies duration for the key expiration. 0 means "never expire".
86+
func (c *ClientEncryptionOptionsBuilder) SetKeyExpiration(expiration time.Duration) *ClientEncryptionOptionsBuilder {
87+
c.Opts = append(c.Opts, func(opts *ClientEncryptionOptions) error {
88+
opts.KeyExpiration = &expiration
89+
90+
return nil
91+
})
92+
93+
return c
94+
}
95+
8396
// BuildTLSConfig specifies tls.Config options for each KMS provider to use to configure TLS on all connections created
8497
// to the KMS provider. The input map should contain a mapping from each KMS provider to a document containing the necessary
8598
// options, as follows:

0 commit comments

Comments
 (0)