remove mock aes, latency and ratelimit wrapper remote services

Signed-off-by: Anish Ramasekar <anish.ramasekar@gmail.com>
This commit is contained in:
Anish Ramasekar 2023-09-27 21:54:29 +00:00
parent 2f5708833a
commit e764e83fe8
No known key found for this signature in database
GPG Key ID: F1F7F3518F1ECB0C
11 changed files with 1 additions and 523 deletions

View File

@ -301,12 +301,9 @@
- baseImportPath: "./vendor/k8s.io/kms/"
allowedImports:
- k8s.io/api
- k8s.io/apimachinery
- k8s.io/client-go
- k8s.io/klog
- k8s.io/kms
- k8s.io/utils
- baseImportPath: "./vendor/k8s.io/endpointslice/"
allowedImports:

View File

@ -296,10 +296,6 @@ rules:
dependencies:
- repository: apimachinery
branch: master
- repository: api
branch: master
- repository: client-go
branch: master
source:
branch: master
dir: staging/src/k8s.io/kms

View File

@ -8,7 +8,6 @@ require (
github.com/gogo/protobuf v1.3.2
google.golang.org/grpc v1.54.0
k8s.io/apimachinery v0.0.0
k8s.io/client-go v0.0.0
k8s.io/klog/v2 v2.100.1
)
@ -18,15 +17,12 @@ require (
golang.org/x/net v0.13.0 // indirect
golang.org/x/sys v0.10.0 // indirect
golang.org/x/text v0.11.0 // indirect
golang.org/x/time v0.3.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect
google.golang.org/protobuf v1.31.0 // indirect
k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect
)
replace (
k8s.io/api => ../api
k8s.io/apimachinery => ../apimachinery
k8s.io/client-go => ../client-go
k8s.io/kms => ../kms
)

View File

@ -6,7 +6,6 @@ github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL
github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34=
github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w=
github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
@ -20,11 +19,9 @@ github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
@ -32,9 +29,6 @@ github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
@ -44,11 +38,8 @@ github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJ
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/onsi/ginkgo/v2 v2.9.4/go.mod h1:gCQYp2Q+kSoIj7ykSVb9nskRSsR6PUj4AiLywzIhbKM=
github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
@ -69,7 +60,7 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.13.0 h1:Nvo8UFsZ8X3BhAC9699Z1j7XQ3rsZnUUm7jfBEk1ueY=
golang.org/x/net v0.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE=
golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -83,7 +74,6 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=

View File

@ -1,96 +0,0 @@
/*
Copyright 2023 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package internal
import (
"context"
"crypto/aes"
"errors"
aestransformer "k8s.io/kms/pkg/encrypt/aes"
"k8s.io/kms/pkg/service"
"k8s.io/kms/pkg/value"
)
var _ service.Service = &mockAESRemoteService{}
const (
mockAnnotationKey = "version.encryption.remote.io"
)
type mockAESRemoteService struct {
keyID string
transformer value.Transformer
dataCtx value.DefaultContext
}
func (s *mockAESRemoteService) Encrypt(ctx context.Context, uid string, plaintext []byte) (*service.EncryptResponse, error) {
out, err := s.transformer.TransformToStorage(ctx, plaintext, s.dataCtx)
if err != nil {
return nil, err
}
return &service.EncryptResponse{
KeyID: s.keyID,
Ciphertext: out,
Annotations: map[string][]byte{
mockAnnotationKey: []byte("1"),
},
}, nil
}
func (s *mockAESRemoteService) Decrypt(ctx context.Context, uid string, req *service.DecryptRequest) ([]byte, error) {
if len(req.Annotations) != 1 {
return nil, errors.New("invalid annotations")
}
if v, ok := req.Annotations[mockAnnotationKey]; !ok || string(v) != "1" {
return nil, errors.New("invalid version in annotations")
}
if req.KeyID != s.keyID {
return nil, errors.New("invalid keyID")
}
from, _, err := s.transformer.TransformFromStorage(ctx, req.Ciphertext, s.dataCtx)
if err != nil {
return nil, err
}
return from, nil
}
func (s *mockAESRemoteService) Status(ctx context.Context) (*service.StatusResponse, error) {
resp := &service.StatusResponse{
Version: "v2beta1",
Healthz: "ok",
KeyID: s.keyID,
}
return resp, nil
}
// NewMockAESService creates an instance of mockAESRemoteService.
func NewMockAESService(aesKey string, keyID string) (service.Service, error) {
block, err := aes.NewCipher([]byte(aesKey))
if err != nil {
return nil, err
}
if len(keyID) == 0 {
return nil, errors.New("invalid keyID")
}
return &mockAESRemoteService{
transformer: aestransformer.NewGCMTransformer(block),
keyID: keyID,
dataCtx: value.DefaultContext([]byte{}),
}, nil
}

View File

@ -1,117 +0,0 @@
/*
Copyright 2023 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package internal
import (
"bytes"
"context"
"testing"
"k8s.io/kms/pkg/service"
)
const (
version = "v2beta1"
testAESKey = "abcdefghijklmnop"
testKeyID = "test-key-id"
testPlaintext = "lorem ipsum dolor sit amet"
)
func testContext(t *testing.T) context.Context {
ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)
return ctx
}
func TestMockAESRemoteService(t *testing.T) {
t.Parallel()
ctx := testContext(t)
plaintext := []byte(testPlaintext)
kmsService, err := NewMockAESService(testAESKey, testKeyID)
if err != nil {
t.Fatal(err)
}
t.Run("should be able to encrypt and decrypt", func(t *testing.T) {
t.Parallel()
encRes, err := kmsService.Encrypt(ctx, "", plaintext)
if err != nil {
t.Fatal(err)
}
if bytes.Equal(plaintext, encRes.Ciphertext) {
t.Fatal("plaintext and ciphertext shouldn't be equal!")
}
decRes, err := kmsService.Decrypt(ctx, "", &service.DecryptRequest{
Ciphertext: encRes.Ciphertext,
KeyID: encRes.KeyID,
Annotations: encRes.Annotations,
})
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(decRes, plaintext) {
t.Errorf("want: %q, have: %q", plaintext, decRes)
}
})
t.Run("should return error when decrypt with an invalid keyID", func(t *testing.T) {
t.Parallel()
encRes, err := kmsService.Encrypt(ctx, "", plaintext)
if err != nil {
t.Fatal(err)
}
if bytes.Equal(plaintext, encRes.Ciphertext) {
t.Fatal("plaintext and ciphertext shouldn't be equal!")
}
_, err = kmsService.Decrypt(ctx, "", &service.DecryptRequest{
Ciphertext: encRes.Ciphertext,
KeyID: encRes.KeyID + "1",
Annotations: encRes.Annotations,
})
if err.Error() != "invalid keyID" {
t.Errorf("should have returned an invalid keyID error. Got %v, requested keyID: %q, remote service keyID: %q", err, encRes.KeyID+"1", testKeyID)
}
})
t.Run("should return status data", func(t *testing.T) {
t.Parallel()
status, err := kmsService.Status(ctx)
if err != nil {
t.Fatal(err)
}
if status.Healthz != "ok" {
t.Errorf("want: %q, have: %q", "ok", status.Healthz)
}
if len(status.KeyID) == 0 {
t.Errorf("want: len(keyID) > 0, have: %d", len(status.KeyID))
}
if status.Version != version {
t.Errorf("want %q, have: %q", version, status.Version)
}
})
}

View File

@ -1,54 +0,0 @@
/*
Copyright 2023 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package internal
import (
"context"
"time"
"k8s.io/kms/pkg/service"
)
type mockLatencyRemoteService struct {
delegate service.Service
latency time.Duration
}
var _ service.Service = &mockLatencyRemoteService{}
func (s *mockLatencyRemoteService) Decrypt(ctx context.Context, uid string, req *service.DecryptRequest) ([]byte, error) {
time.Sleep(s.latency)
return s.delegate.Decrypt(ctx, uid, req)
}
func (s *mockLatencyRemoteService) Encrypt(ctx context.Context, uid string, data []byte) (*service.EncryptResponse, error) {
time.Sleep(s.latency)
return s.delegate.Encrypt(ctx, uid, data)
}
func (s *mockLatencyRemoteService) Status(ctx context.Context) (*service.StatusResponse, error) {
// Passthrough here, not adding any delays for status as delays are usually negligible compare to encrypt and decrypt requests.
return s.delegate.Status(ctx)
}
// NewMockLatencyService creates an instance of mockLatencyRemoteService.
func NewMockLatencyService(delegate service.Service, latency time.Duration) service.Service {
return &mockLatencyRemoteService{
delegate: delegate,
latency: latency,
}
}

View File

@ -1,99 +0,0 @@
/*
Copyright 2023 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package internal
import (
"bytes"
"testing"
"time"
"k8s.io/kms/pkg/service"
)
const (
testLatencyInMillisecond = 100 * time.Millisecond
)
func TestMockLatencyRemoteService(t *testing.T) {
t.Parallel()
ctx := testContext(t)
plaintext := []byte(testPlaintext)
aesService, err := NewMockAESService(testAESKey, testKeyID)
if err != nil {
t.Fatal(err)
}
kmsService := NewMockLatencyService(aesService, testLatencyInMillisecond)
t.Run("should be able to encrypt and decrypt with some known latency", func(t *testing.T) {
t.Parallel()
start := time.Now()
encRes, err := kmsService.Encrypt(ctx, "", plaintext)
if err != nil {
t.Fatal(err)
}
duration := time.Since(start)
if bytes.Equal(plaintext, encRes.Ciphertext) {
t.Fatal("plaintext and ciphertext shouldn't be equal!")
}
// Max is set to 3s to limit the risk of a CPU limited CI node taking a long time to do encryption.
if duration < testLatencyInMillisecond || duration > 3*time.Second {
t.Errorf("duration for encrypt should be around: %q, have: %q", testLatencyInMillisecond, duration)
}
start = time.Now()
decRes, err := kmsService.Decrypt(ctx, "", &service.DecryptRequest{
Ciphertext: encRes.Ciphertext,
KeyID: encRes.KeyID,
Annotations: encRes.Annotations,
})
if err != nil {
t.Fatal(err)
}
duration = time.Since(start)
if !bytes.Equal(decRes, plaintext) {
t.Errorf("want: %q, have: %q", plaintext, decRes)
}
if duration < testLatencyInMillisecond || duration > 3*time.Second {
t.Errorf("duration decrypt should be around: %q, have: %q", testLatencyInMillisecond, duration)
}
})
t.Run("should return status data", func(t *testing.T) {
t.Parallel()
start := time.Now()
status, err := kmsService.Status(ctx)
if err != nil {
t.Fatal(err)
}
duration := time.Since(start)
if status.Healthz != "ok" {
t.Errorf("want: %q, have: %q", "ok", status.Healthz)
}
if len(status.KeyID) == 0 {
t.Errorf("want: len(keyID) > 0, have: %d", len(status.KeyID))
}
if status.Version != version {
t.Errorf("want %q, have: %q", version, status.Version)
}
if duration > 3*time.Second {
t.Errorf("duration status should be less than: 3s, have: %q", duration)
}
})
}

View File

@ -1,60 +0,0 @@
/*
Copyright 2023 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package internal
import (
"context"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"k8s.io/client-go/util/flowcontrol"
"k8s.io/kms/pkg/service"
)
type mockRateLimitRemoteService struct {
delegate service.Service
limiter flowcontrol.RateLimiter
}
var _ service.Service = &mockRateLimitRemoteService{}
func (s *mockRateLimitRemoteService) Decrypt(ctx context.Context, uid string, req *service.DecryptRequest) ([]byte, error) {
if !s.limiter.TryAccept() {
return nil, status.New(codes.ResourceExhausted, "remote decrypt rate limit exceeded").Err()
}
return s.delegate.Decrypt(ctx, uid, req)
}
func (s *mockRateLimitRemoteService) Encrypt(ctx context.Context, uid string, data []byte) (*service.EncryptResponse, error) {
if !s.limiter.TryAccept() {
return nil, status.New(codes.ResourceExhausted, "remote encrypt rate limit exceeded").Err()
}
return s.delegate.Encrypt(ctx, uid, data)
}
func (s *mockRateLimitRemoteService) Status(ctx context.Context) (*service.StatusResponse, error) {
// Passthrough here, not adding any rate limiting for status as rate limits are usually for encrypt and decrypt requests.
return s.delegate.Status(ctx)
}
// NewMockRateLimitService creates an instance of mockRateLimitRemoteService.
func NewMockRateLimitService(delegate service.Service, qps float32, burst int) service.Service {
return &mockRateLimitRemoteService{
delegate: delegate,
limiter: flowcontrol.NewTokenBucketRateLimiter(qps, burst),
}
}

View File

@ -1,74 +0,0 @@
/*
Copyright 2023 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package internal
import (
"bytes"
"testing"
)
const (
testQPS = 1
// testBurst should be no more than 9 since 9*100millisecond (test latency) = 900ms, which guarantees there is enough bursts per second.
testBurst = 5
)
func TestMockRateLimitRemoteService(t *testing.T) {
t.Parallel()
ctx := testContext(t)
plaintext := []byte(testPlaintext)
aesService, err := NewMockAESService(testAESKey, testKeyID)
if err != nil {
t.Fatal(err)
}
mockLatencyService := NewMockLatencyService(aesService, testLatencyInMillisecond)
kmsService := NewMockRateLimitService(mockLatencyService, testQPS, testBurst)
t.Run("should hit rate limit", func(t *testing.T) {
rateLimitExceeded := false
for i := 0; i < 100; i++ {
encRes, err := kmsService.Encrypt(ctx, "", plaintext)
if i >= testBurst {
if err != nil {
if err.Error() != "rpc error: code = ResourceExhausted desc = remote encrypt rate limit exceeded" {
t.Fatalf("should have failed with rate limit exceeded %d, have err: %v", testBurst, err)
}
rateLimitExceeded = true
} else {
if bytes.Equal(plaintext, encRes.Ciphertext) {
t.Fatal("plaintext and ciphertext shouldn't be equal!")
}
}
} else {
if err != nil {
t.Fatalf("err: %v, i: %d", err, i)
}
if bytes.Equal(plaintext, encRes.Ciphertext) {
t.Fatal("plaintext and ciphertext shouldn't be equal!")
}
}
// status should not hit any rate limit
_, err = kmsService.Status(ctx)
if err != nil {
t.Fatal(err)
}
}
if !rateLimitExceeded {
t.Errorf("should have reached the rate limit of %d", testBurst)
}
})
}

View File

@ -18,7 +18,6 @@ WORKDIR /workspace
# Copy the source
COPY apimachinery/ apimachinery/
COPY client-go/ client-go/
COPY kms/ kms/
WORKDIR /workspace/kms/internal/plugins/_mock