mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-06 10:43:56 +00:00
remove mock aes, latency and ratelimit wrapper remote services
Signed-off-by: Anish Ramasekar <anish.ramasekar@gmail.com>
This commit is contained in:
parent
2f5708833a
commit
e764e83fe8
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
)
|
||||
|
12
staging/src/k8s.io/kms/go.sum
generated
12
staging/src/k8s.io/kms/go.sum
generated
@ -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=
|
||||
|
@ -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
|
||||
}
|
@ -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)
|
||||
}
|
||||
})
|
||||
}
|
@ -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,
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
})
|
||||
}
|
@ -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),
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
})
|
||||
}
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user