@@ -24,15 +24,16 @@ import (
24
24
"iter"
25
25
"log/slog"
26
26
"slices"
27
+ "time"
27
28
28
29
"filippo.io/age"
29
30
"github.com/gravitational/trace"
30
31
31
32
recordingencryptionv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/recordingencryption/v1"
32
33
"github.com/gravitational/teleport/api/types"
34
+ "github.com/gravitational/teleport/api/utils/retryutils"
33
35
"github.com/gravitational/teleport/lib/backend"
34
36
"github.com/gravitational/teleport/lib/cryptosuites"
35
- "github.com/gravitational/teleport/lib/events"
36
37
"github.com/gravitational/teleport/lib/services"
37
38
)
38
39
@@ -78,7 +79,6 @@ type Manager struct {
78
79
79
80
logger * slog.Logger
80
81
keyStore EncryptionKeyStore
81
- uploader events.MultipartUploader
82
82
}
83
83
84
84
// ensureActiveRecordingEncryption returns the configured RecordingEncryption resource if it exists with active keys. If it does not,
@@ -301,34 +301,56 @@ type RecordingEncryptionResolver interface {
301
301
ResolveRecordingEncryption (ctx context.Context ) (* recordingencryptionv1.RecordingEncryption , error )
302
302
}
303
303
304
- // WatchConfig captures required dependencies for building a RecordingEncyprtion watcher that
304
+ // WatchConfig captures required dependencies for building a RecordingEncryption watcher that
305
305
// automatically resolves state.
306
306
type WatchConfig struct {
307
307
Events types.Events
308
308
Resolver RecordingEncryptionResolver
309
309
ClusterConfig services.ClusterConfiguration
310
310
Logger * slog.Logger
311
- LockConfig backend.RunWhileLockedConfig
311
+ LockConfig * backend.RunWhileLockedConfig
312
312
}
313
313
314
- // Watch creates a watcher responsible for responding to changes in the RecordingEncryption
315
- // resource. This is how auth servers cooperate and ensure there are accessible wrapped keys for each unique
316
- // keystore configuration in a cluster.
317
- func Watch (ctx context.Context , cfg WatchConfig ) error {
314
+ // A Watcher watches for changes to the RecordingEncryption resource and resolves the state for the calling
315
+ // auth server.
316
+ type Watcher struct {
317
+ events types.Events
318
+ resolver RecordingEncryptionResolver
319
+ clusterConfig services.ClusterConfiguration
320
+ logger * slog.Logger
321
+ lockConfig * backend.RunWhileLockedConfig
322
+ }
323
+
324
+ // NewWatcher returns a new Watcher.
325
+ func NewWatcher (cfg WatchConfig ) (* Watcher , error ) {
318
326
switch {
319
327
case cfg .Events == nil :
320
- return trace .BadParameter ("events is required" )
328
+ return nil , trace .BadParameter ("events is required" )
321
329
case cfg .Resolver == nil :
322
- return trace .BadParameter ("recording encryption resolver is required" )
330
+ return nil , trace .BadParameter ("recording encryption resolver is required" )
323
331
case cfg .ClusterConfig == nil :
324
- return trace .BadParameter ("cluster config backend is required" )
332
+ return nil , trace .BadParameter ("cluster config backend is required" )
333
+ case cfg .LockConfig == nil :
334
+ return nil , trace .BadParameter ("lock config is required" )
325
335
}
326
336
if cfg .Logger == nil {
327
337
cfg .Logger = slog .Default ()
328
338
}
329
339
330
- cfg .Logger .DebugContext (ctx , "creating recording_encryption watcher" )
331
- w , err := cfg .Events .NewWatcher (ctx , types.Watch {
340
+ return & Watcher {
341
+ events : cfg .Events ,
342
+ resolver : cfg .Resolver ,
343
+ clusterConfig : cfg .ClusterConfig ,
344
+ logger : cfg .Logger ,
345
+ lockConfig : cfg .LockConfig ,
346
+ }, nil
347
+ }
348
+
349
+ // Watch creates a watcher responsible for responding to changes in the RecordingEncryption resource.
350
+ // This is how auth servers cooperate and ensure there are accessible wrapped keys for each unique keystore
351
+ // configuration in a cluster.
352
+ func (w * Watcher ) Run (ctx context.Context ) error {
353
+ watch , err := w .events .NewWatcher (ctx , types.Watch {
332
354
Name : "recording_encryption_watcher" ,
333
355
Kinds : []types.WatchKind {
334
356
{
@@ -340,55 +362,51 @@ func Watch(ctx context.Context, cfg WatchConfig) error {
340
362
return trace .Wrap (err )
341
363
}
342
364
343
- go func () {
344
- for {
345
- select {
346
- case ev := <- w .Events ():
347
- if ev .Type != types .OpPut {
348
- continue
349
- }
350
- const retries = 3
351
- for tries := range retries {
352
- err := handleRecordingEncryptionChange (ctx , cfg )
353
- if err == nil {
354
- break
355
- }
356
-
357
- cfg .Logger .ErrorContext (ctx , "failed to handle session recording config change" , "error" , err , "remaining_tries" , retries - tries - 1 )
365
+ for {
366
+ select {
367
+ case ev := <- watch .Events ():
368
+ if ev .Type != types .OpPut {
369
+ continue
370
+ }
371
+ const retries = 3
372
+ for tries := range retries {
373
+ err := w .handleRecordingEncryptionChange (ctx )
374
+ if err == nil {
375
+ break
358
376
}
359
377
360
- case <- w .Done ():
361
- cfg .Logger .DebugContext (ctx , "no longer watching recording_encryption" )
362
- return
378
+ w .logger .ErrorContext (ctx , "failed to handle session recording config change" , "error" , err , "remaining_tries" , retries - tries - 1 )
379
+ <- time .After (retryutils .SeventhJitter (time .Second * 10 ))
363
380
}
364
- }
365
- }()
366
381
367
- return nil
382
+ case <- watch .Done ():
383
+ return trace .Wrap (watch .Error ())
384
+ }
385
+ }
368
386
}
369
387
370
388
// this helper handles reacting to individual Put events on the RecordingEncryption resource and updates the
371
389
// SessionRecordingConfig with the results, if necessary
372
- func handleRecordingEncryptionChange (ctx context.Context , cfg WatchConfig ) error {
373
- return trace .Wrap (backend .RunWhileLocked (ctx , cfg . LockConfig , func (ctx context.Context ) error {
374
- recConfig , err := cfg . ClusterConfig .GetSessionRecordingConfig (ctx )
390
+ func ( w * Watcher ) handleRecordingEncryptionChange (ctx context.Context ) error {
391
+ return trace .Wrap (backend .RunWhileLocked (ctx , * w . lockConfig , func (ctx context.Context ) error {
392
+ recConfig , err := w . clusterConfig .GetSessionRecordingConfig (ctx )
375
393
if err != nil {
376
394
return trace .Wrap (err , "fetching recording config" )
377
395
}
378
396
379
397
if ! recConfig .GetEncrypted () {
380
- cfg . Logger .DebugContext (ctx , "session recording encryption disabled, skip resolving keys" )
398
+ w . logger .DebugContext (ctx , "session recording encryption disabled, skip resolving keys" )
381
399
return nil
382
400
}
383
401
384
- encryption , err := cfg . Resolver .ResolveRecordingEncryption (ctx )
402
+ encryption , err := w . resolver .ResolveRecordingEncryption (ctx )
385
403
if err != nil {
386
- cfg . Logger .ErrorContext (ctx , "failed to resolve recording encryption state" , "error" , err )
404
+ w . logger .ErrorContext (ctx , "failed to resolve recording encryption state" , "error" , err )
387
405
return trace .Wrap (err , "resolving recording encryption" )
388
406
}
389
407
390
408
if recConfig .SetEncryptionKeys (GetAgeEncryptionKeys (encryption .GetSpec ().ActiveKeys )) {
391
- _ , err = cfg . ClusterConfig .UpdateSessionRecordingConfig (ctx , recConfig )
409
+ _ , err = w . clusterConfig .UpdateSessionRecordingConfig (ctx , recConfig )
392
410
return trace .Wrap (err , "updating encryption keys" )
393
411
}
394
412
0 commit comments