Skip to content

Commit

Permalink
sql: encrypt Tokens by default (#467)
Browse files Browse the repository at this point in the history
Co-authored-by: Eric Promislow <[email protected]>
  • Loading branch information
moio and ericpromislow authored Feb 3, 2025
1 parent d794bfe commit 6a46a1e
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 2 deletions.
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ Meaning and behavior are the same unless otherwise specified.

Note that, if SQLite caching of resources is enabled, some of the data
can be stored in disk, in either encrypted or plain text forms based on:
- by default, Secrets are always encrypted
- by default, Secrets and Rancher Tokens (`management.cattle.io/v3, Kind=Token`) are always encrypted
- if the environment variable `CATTLE_ENCRYPT_CACHE_ALL` is set to "true",
all resources are encrypted
- regardless of the setting's value, any filterable/sortable columns are stored
Expand Down Expand Up @@ -842,4 +842,3 @@ export KUBEBUILDER_ASSETS=$(setup-envtest use -p path)
# Versioning
See [VERSION.md](VERSION.md).
5 changes: 5 additions & 0 deletions pkg/sqlcache/informer/factory/informer_factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ var defaultEncryptedResourceTypes = map[schema.GroupVersionKind]struct{}{
Version: "v1",
Kind: "Secret",
}: {},
{
Group: "management.cattle.io",
Version: "v3",
Kind: "Token",
}: {},
}

// NewCacheFactory returns an informer factory instance
Expand Down
96 changes: 96 additions & 0 deletions pkg/sqlcache/informer/factory/informer_factory_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,102 @@ func TestCacheFor(t *testing.T) {
assert.Equal(t, expectedC, c)
time.Sleep(1 * time.Second)
}})

tests = append(tests, testCase{description: "CacheFor() should encrypt v1 Secrets", test: func(t *testing.T) {
dbClient := NewMockDBClient(gomock.NewController(t))
dynamicClient := NewMockResourceInterface(gomock.NewController(t))
fields := [][]string{{"something"}}
expectedGVK := schema.GroupVersionKind{
Group: "",
Version: "v1",
Kind: "Secret",
}
sii := NewMockSharedIndexInformer(gomock.NewController(t))
sii.EXPECT().HasSynced().Return(true)
sii.EXPECT().Run(gomock.Any()).MinTimes(1).AnyTimes()
sii.EXPECT().SetWatchErrorHandler(gomock.Any())
i := &informer.Informer{
// need to set this so Run function is not nil
SharedIndexInformer: sii,
}
expectedC := Cache{
ByOptionsLister: i,
}
testNewInformer := func(client dynamic.ResourceInterface, fields [][]string, transform cache.TransformFunc, gvk schema.GroupVersionKind, db sqlStore.DBClient, shouldEncrypt, namespaced bool) (*informer.Informer, error) {
assert.Equal(t, client, dynamicClient)
assert.Equal(t, fields, fields)
assert.Equal(t, expectedGVK, gvk)
assert.Equal(t, db, dbClient)
assert.Equal(t, true, shouldEncrypt)
return i, nil
}
f := &CacheFactory{
dbClient: dbClient,
stopCh: make(chan struct{}),
newInformer: testNewInformer,
encryptAll: false,
informers: map[schema.GroupVersionKind]*guardedInformer{},
}

go func() {
time.Sleep(10 * time.Second)
close(f.stopCh)
}()
var c Cache
var err error
c, err = f.CacheFor(fields, nil, dynamicClient, expectedGVK, false, true)
assert.Nil(t, err)
assert.Equal(t, expectedC, c)
time.Sleep(1 * time.Second)
}})
tests = append(tests, testCase{description: "CacheFor() should encrypt management.cattle.io tokens", test: func(t *testing.T) {
dbClient := NewMockDBClient(gomock.NewController(t))
dynamicClient := NewMockResourceInterface(gomock.NewController(t))
fields := [][]string{{"something"}}
expectedGVK := schema.GroupVersionKind{
Group: "management.cattle.io",
Version: "v3",
Kind: "Token",
}
sii := NewMockSharedIndexInformer(gomock.NewController(t))
sii.EXPECT().HasSynced().Return(true)
sii.EXPECT().Run(gomock.Any()).MinTimes(1).AnyTimes()
sii.EXPECT().SetWatchErrorHandler(gomock.Any())
i := &informer.Informer{
// need to set this so Run function is not nil
SharedIndexInformer: sii,
}
expectedC := Cache{
ByOptionsLister: i,
}
testNewInformer := func(client dynamic.ResourceInterface, fields [][]string, transform cache.TransformFunc, gvk schema.GroupVersionKind, db sqlStore.DBClient, shouldEncrypt, namespaced bool) (*informer.Informer, error) {
assert.Equal(t, client, dynamicClient)
assert.Equal(t, fields, fields)
assert.Equal(t, expectedGVK, gvk)
assert.Equal(t, db, dbClient)
assert.Equal(t, true, shouldEncrypt)
return i, nil
}
f := &CacheFactory{
dbClient: dbClient,
stopCh: make(chan struct{}),
newInformer: testNewInformer,
encryptAll: false,
informers: map[schema.GroupVersionKind]*guardedInformer{},
}

go func() {
time.Sleep(10 * time.Second)
close(f.stopCh)
}()
var c Cache
var err error
c, err = f.CacheFor(fields, nil, dynamicClient, expectedGVK, false, true)
assert.Nil(t, err)
assert.Equal(t, expectedC, c)
time.Sleep(1 * time.Second)
}})

tests = append(tests, testCase{description: "CacheFor() with no errors returned, HasSync returning true, stopCh not closed, and transform func should return no error", test: func(t *testing.T) {
dbClient := NewMockDBClient(gomock.NewController(t))
dynamicClient := NewMockResourceInterface(gomock.NewController(t))
Expand Down

0 comments on commit 6a46a1e

Please sign in to comment.