Merge pull request #114922 from ibihim/kmsv2-interface-move

[KMSv2] apiserver/kmsv2: mv Service interface into kmsv2

Kubernetes-commit: f7b02260f6a8cc7826040d5fcd265bc15672880f
This commit is contained in:
Kubernetes Publisher 2023-01-17 10:10:33 -08:00
commit 8f0891c85c
8 changed files with 45 additions and 71 deletions

8
go.mod
View File

@ -44,10 +44,10 @@ require (
gopkg.in/square/go-jose.v2 v2.2.2
k8s.io/api v0.0.0-20230112183318-59fcd23597fd
k8s.io/apimachinery v0.0.0-20230112182327-235f5123de4a
k8s.io/client-go v0.0.0-20230113000324-241dfe363021
k8s.io/client-go v0.0.0-20230116012449-228b004f4a92
k8s.io/component-base v0.0.0-20230112192324-33f62c7b2818
k8s.io/klog/v2 v2.80.1
k8s.io/kms v0.0.0-20230107081413-fd373b9a5aa5
k8s.io/kms v0.0.0-20230117203143-407acb40b4f8
k8s.io/kube-openapi v0.0.0-20230109183929-3758b55a6596
k8s.io/utils v0.0.0-20221107191617-1a15be271d1d
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.35
@ -124,7 +124,7 @@ require (
replace (
k8s.io/api => k8s.io/api v0.0.0-20230112183318-59fcd23597fd
k8s.io/apimachinery => k8s.io/apimachinery v0.0.0-20230112182327-235f5123de4a
k8s.io/client-go => k8s.io/client-go v0.0.0-20230113000324-241dfe363021
k8s.io/client-go => k8s.io/client-go v0.0.0-20230116012449-228b004f4a92
k8s.io/component-base => k8s.io/component-base v0.0.0-20230112192324-33f62c7b2818
k8s.io/kms => k8s.io/kms v0.0.0-20230107081413-fd373b9a5aa5
k8s.io/kms => k8s.io/kms v0.0.0-20230117203143-407acb40b4f8
)

8
go.sum
View File

@ -994,14 +994,14 @@ k8s.io/api v0.0.0-20230112183318-59fcd23597fd h1:Y/vljv797SrqMUZ4KwQaIDcz+lecu07
k8s.io/api v0.0.0-20230112183318-59fcd23597fd/go.mod h1:K1fbar68K91an+8RbH9eJWJRnoXQ5rugf6J5wsGMMWg=
k8s.io/apimachinery v0.0.0-20230112182327-235f5123de4a h1:ztM2zo2xo0w+WBKGJ/V/TnavQfbZnADVA5s4p3LGDpo=
k8s.io/apimachinery v0.0.0-20230112182327-235f5123de4a/go.mod h1:Kq932aOItR+rI/aiAVDXxxdRFNf0eLnI0gZmXJ6hl3o=
k8s.io/client-go v0.0.0-20230113000324-241dfe363021 h1:ApG3Cidw9Kn6WYh/56MjFtrK74S9h/cbYF2bPf6AEVY=
k8s.io/client-go v0.0.0-20230113000324-241dfe363021/go.mod h1:yGx/VWWKjooWFIfibkKEt0Vf6gG9wDALmEzcgJv5jPs=
k8s.io/client-go v0.0.0-20230116012449-228b004f4a92 h1:ufPl+2CEizC47k/ptJxbryxNF+EpJPG3aDIO6qUkXFE=
k8s.io/client-go v0.0.0-20230116012449-228b004f4a92/go.mod h1:yGx/VWWKjooWFIfibkKEt0Vf6gG9wDALmEzcgJv5jPs=
k8s.io/component-base v0.0.0-20230112192324-33f62c7b2818 h1:sZ5awJx2PpXaOwNSEu8Pq6zovP1+YG/nWZpagmpDRcs=
k8s.io/component-base v0.0.0-20230112192324-33f62c7b2818/go.mod h1:6IeVfLNdhjJkJFQHYMuwk7dgkOLA3Pt+Y7j7Md1d+CA=
k8s.io/klog/v2 v2.80.1 h1:atnLQ121W371wYYFawwYx1aEY2eUfs4l3J72wtgAwV4=
k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
k8s.io/kms v0.0.0-20230107081413-fd373b9a5aa5 h1:lIrmdsSdF5Z8YODvH6hozkg5tUWRAtojzj1gyqwk5sc=
k8s.io/kms v0.0.0-20230107081413-fd373b9a5aa5/go.mod h1:8nNxRLuUXpWlFuo+Xt4yUheyyZDJ/DY6Ypd0EEmXypg=
k8s.io/kms v0.0.0-20230117203143-407acb40b4f8 h1:oYOLi+NfW2BoplN1w5lO0NdBaQpV5Oe8C2XmFkjFi8g=
k8s.io/kms v0.0.0-20230117203143-407acb40b4f8/go.mod h1:ND+WCT0K/L1kWk7CwCkd4wRBKmtGDBjslBC6X8QZEuU=
k8s.io/kube-openapi v0.0.0-20230109183929-3758b55a6596 h1:8cNCQs+WqqnSpZ7y0LMQPKD+RZUHU17VqLPMW3qxnxc=
k8s.io/kube-openapi v0.0.0-20230109183929-3758b55a6596/go.mod h1:/BYxry62FuDzmI+i9B+X2pqfySRmSOW2ARmj5Zbqhj0=
k8s.io/utils v0.0.0-20221107191617-1a15be271d1d h1:0Smp/HP1OH4Rvhe+4B8nWGERtlqAGSftbSbbmm45oFs=

View File

@ -48,6 +48,7 @@ import (
"k8s.io/apiserver/pkg/storage/value/encrypt/identity"
"k8s.io/apiserver/pkg/storage/value/encrypt/secretbox"
utilfeature "k8s.io/apiserver/pkg/util/feature"
kmsservice "k8s.io/kms/service"
)
const (
@ -85,7 +86,7 @@ type kmsPluginProbe struct {
type kmsv2PluginProbe struct {
name string
ttl time.Duration
service envelopekmsv2.Service
service kmsservice.Service
lastResponse *kmsPluginHealthzResponse
l *sync.Mutex
}
@ -284,7 +285,7 @@ func (h *kmsv2PluginProbe) check(ctx context.Context) error {
}
// isKMSv2ProviderHealthy checks if the KMSv2-Plugin is healthy.
func isKMSv2ProviderHealthy(name string, response *envelopekmsv2.StatusResponse) error {
func isKMSv2ProviderHealthy(name string, response *kmsservice.StatusResponse) error {
var errs []error
if response.Healthz != "ok" {
errs = append(errs, fmt.Errorf("got unexpected healthz status: %s", response.Healthz))

View File

@ -32,9 +32,9 @@ import (
"k8s.io/apiserver/pkg/features"
"k8s.io/apiserver/pkg/storage/value"
"k8s.io/apiserver/pkg/storage/value/encrypt/envelope"
envelopekmsv2 "k8s.io/apiserver/pkg/storage/value/encrypt/envelope/kmsv2"
utilfeature "k8s.io/apiserver/pkg/util/feature"
featuregatetesting "k8s.io/component-base/featuregate/testing"
kmsservice "k8s.io/kms/service"
)
const (
@ -68,28 +68,28 @@ type testKMSv2EnvelopeService struct {
err error
}
func (t *testKMSv2EnvelopeService) Decrypt(ctx context.Context, uid string, req *envelopekmsv2.DecryptRequest) ([]byte, error) {
func (t *testKMSv2EnvelopeService) Decrypt(ctx context.Context, uid string, req *kmsservice.DecryptRequest) ([]byte, error) {
if t.err != nil {
return nil, t.err
}
return base64.StdEncoding.DecodeString(string(req.Ciphertext))
}
func (t *testKMSv2EnvelopeService) Encrypt(ctx context.Context, uid string, data []byte) (*envelopekmsv2.EncryptResponse, error) {
func (t *testKMSv2EnvelopeService) Encrypt(ctx context.Context, uid string, data []byte) (*kmsservice.EncryptResponse, error) {
if t.err != nil {
return nil, t.err
}
return &envelopekmsv2.EncryptResponse{
return &kmsservice.EncryptResponse{
Ciphertext: []byte(base64.StdEncoding.EncodeToString(data)),
KeyID: "1",
}, nil
}
func (t *testKMSv2EnvelopeService) Status(ctx context.Context) (*envelopekmsv2.StatusResponse, error) {
func (t *testKMSv2EnvelopeService) Status(ctx context.Context) (*kmsservice.StatusResponse, error) {
if t.err != nil {
return nil, t.err
}
return &envelopekmsv2.StatusResponse{Healthz: "ok", KeyID: "1", Version: "v2alpha1"}, nil
return &kmsservice.StatusResponse{Healthz: "ok", KeyID: "1", Version: "v2alpha1"}, nil
}
// The factory method to create mock envelope service.
@ -103,12 +103,12 @@ func newMockErrorEnvelopeService(endpoint string, timeout time.Duration) (envelo
}
// The factory method to create mock envelope kmsv2 service.
func newMockEnvelopeKMSv2Service(ctx context.Context, endpoint string, timeout time.Duration) (envelopekmsv2.Service, error) {
func newMockEnvelopeKMSv2Service(ctx context.Context, endpoint string, timeout time.Duration) (kmsservice.Service, error) {
return &testKMSv2EnvelopeService{nil}, nil
}
// The factory method to create mock envelope kmsv2 service which always returns error.
func newMockErrorEnvelopeKMSv2Service(endpoint string, timeout time.Duration) (envelopekmsv2.Service, error) {
func newMockErrorEnvelopeKMSv2Service(endpoint string, timeout time.Duration) (kmsservice.Service, error) {
return &testKMSv2EnvelopeService{errors.New("test")}, nil
}
@ -773,23 +773,23 @@ func getTransformerFromEncryptionConfig(t *testing.T, encryptionConfigPath strin
func TestIsKMSv2ProviderHealthyError(t *testing.T) {
testCases := []struct {
desc string
statusResponse *envelopekmsv2.StatusResponse
statusResponse *kmsservice.StatusResponse
}{
{
desc: "healthz status is not ok",
statusResponse: &envelopekmsv2.StatusResponse{
statusResponse: &kmsservice.StatusResponse{
Healthz: "unhealthy",
},
},
{
desc: "version is not v2alpha1",
statusResponse: &envelopekmsv2.StatusResponse{
statusResponse: &kmsservice.StatusResponse{
Version: "v1beta1",
},
},
{
desc: "missing keyID",
statusResponse: &envelopekmsv2.StatusResponse{
statusResponse: &kmsservice.StatusResponse{
Healthz: "ok",
Version: "v2alpha1",
},

View File

@ -35,6 +35,7 @@ import (
kmstypes "k8s.io/apiserver/pkg/storage/value/encrypt/envelope/kmsv2/v2alpha1"
"k8s.io/apiserver/pkg/storage/value/encrypt/envelope/metrics"
"k8s.io/klog/v2"
kmsservice "k8s.io/kms/service"
"k8s.io/utils/lru"
)
@ -49,18 +50,8 @@ const (
encryptedDEKMaxSize = 1 * 1024 // 1 kB
)
// Service allows encrypting and decrypting data using an external Key Management Service.
type Service interface {
// Decrypt a given bytearray to obtain the original data as bytes.
Decrypt(ctx context.Context, uid string, req *DecryptRequest) ([]byte, error)
// Encrypt bytes to a ciphertext.
Encrypt(ctx context.Context, uid string, data []byte) (*EncryptResponse, error)
// Status returns the status of the KMS.
Status(ctx context.Context) (*StatusResponse, error)
}
type envelopeTransformer struct {
envelopeService Service
envelopeService kmsservice.Service
// transformers is a thread-safe LRU cache which caches decrypted DEKs indexed by their encrypted form.
transformers *lru.Cache
@ -72,32 +63,11 @@ type envelopeTransformer struct {
cacheEnabled bool
}
// EncryptResponse is the response from the Envelope service when encrypting data.
type EncryptResponse struct {
Ciphertext []byte
KeyID string
Annotations map[string][]byte
}
// DecryptRequest is the request to the Envelope service when decrypting data.
type DecryptRequest struct {
Ciphertext []byte
KeyID string
Annotations map[string][]byte
}
// StatusResponse is the response from the Envelope service when getting the status of the service.
type StatusResponse struct {
Version string
Healthz string
KeyID string
}
// NewEnvelopeTransformer returns a transformer which implements a KEK-DEK based envelope encryption scheme.
// It uses envelopeService to encrypt and decrypt DEKs. Respective DEKs (in encrypted form) are prepended to
// the data items they encrypt. A cache (of size cacheSize) is maintained to store the most recently
// used decrypted DEKs in memory.
func NewEnvelopeTransformer(envelopeService Service, cacheSize int, baseTransformerFunc func(cipher.Block) value.Transformer) value.Transformer {
func NewEnvelopeTransformer(envelopeService kmsservice.Service, cacheSize int, baseTransformerFunc func(cipher.Block) value.Transformer) value.Transformer {
var cache *lru.Cache
if cacheSize > 0 {
@ -133,7 +103,7 @@ func (t *envelopeTransformer) TransformFromStorage(ctx context.Context, data []b
}
uid := string(uuid.NewUUID())
klog.V(6).InfoS("Decrypting content using envelope service", "uid", uid, "key", string(dataCtx.AuthenticatedData()))
key, err := t.envelopeService.Decrypt(ctx, uid, &DecryptRequest{
key, err := t.envelopeService.Decrypt(ctx, uid, &kmsservice.DecryptRequest{
Ciphertext: encryptedObject.EncryptedDEK,
KeyID: encryptedObject.KeyID,
Annotations: encryptedObject.Annotations,

View File

@ -30,6 +30,7 @@ import (
"k8s.io/apiserver/pkg/storage/value"
aestransformer "k8s.io/apiserver/pkg/storage/value/encrypt/aes"
kmstypes "k8s.io/apiserver/pkg/storage/value/encrypt/envelope/kmsv2/v2alpha1"
kmsservice "k8s.io/kms/service"
)
const (
@ -46,7 +47,7 @@ type testEnvelopeService struct {
keyVersion string
}
func (t *testEnvelopeService) Decrypt(ctx context.Context, uid string, req *DecryptRequest) ([]byte, error) {
func (t *testEnvelopeService) Decrypt(ctx context.Context, uid string, req *kmsservice.DecryptRequest) ([]byte, error) {
if t.disabled {
return nil, fmt.Errorf("Envelope service was disabled")
}
@ -59,7 +60,7 @@ func (t *testEnvelopeService) Decrypt(ctx context.Context, uid string, req *Decr
return base64.StdEncoding.DecodeString(string(req.Ciphertext))
}
func (t *testEnvelopeService) Encrypt(ctx context.Context, uid string, data []byte) (*EncryptResponse, error) {
func (t *testEnvelopeService) Encrypt(ctx context.Context, uid string, data []byte) (*kmsservice.EncryptResponse, error) {
if t.disabled {
return nil, fmt.Errorf("Envelope service was disabled")
}
@ -74,14 +75,14 @@ func (t *testEnvelopeService) Encrypt(ctx context.Context, uid string, data []by
} else {
annotations["local-kek.kms.kubernetes.io"] = []byte("encrypted-local-kek")
}
return &EncryptResponse{Ciphertext: []byte(base64.StdEncoding.EncodeToString(data)), KeyID: t.keyVersion, Annotations: annotations}, nil
return &kmsservice.EncryptResponse{Ciphertext: []byte(base64.StdEncoding.EncodeToString(data)), KeyID: t.keyVersion, Annotations: annotations}, nil
}
func (t *testEnvelopeService) Status(ctx context.Context) (*StatusResponse, error) {
func (t *testEnvelopeService) Status(ctx context.Context) (*kmsservice.StatusResponse, error) {
if t.disabled {
return nil, fmt.Errorf("Envelope service was disabled")
}
return &StatusResponse{KeyID: t.keyVersion}, nil
return &kmsservice.StatusResponse{KeyID: t.keyVersion}, nil
}
func (t *testEnvelopeService) SetDisabledStatus(status bool) {

View File

@ -30,6 +30,7 @@ import (
"k8s.io/apiserver/pkg/storage/value/encrypt/envelope/util"
"k8s.io/klog/v2"
kmsapi "k8s.io/kms/apis/v2alpha1"
kmsservice "k8s.io/kms/service"
)
const (
@ -45,7 +46,7 @@ type gRPCService struct {
}
// NewGRPCService returns an envelope.Service which use gRPC to communicate the remote KMS provider.
func NewGRPCService(ctx context.Context, endpoint string, callTimeout time.Duration) (Service, error) {
func NewGRPCService(ctx context.Context, endpoint string, callTimeout time.Duration) (kmsservice.Service, error) {
klog.V(4).Infof("Configure KMS provider with endpoint: %s", endpoint)
addr, err := util.ParseEndpoint(endpoint)
@ -88,7 +89,7 @@ func NewGRPCService(ctx context.Context, endpoint string, callTimeout time.Durat
}
// Decrypt a given data string to obtain the original byte data.
func (g *gRPCService) Decrypt(ctx context.Context, uid string, req *DecryptRequest) ([]byte, error) {
func (g *gRPCService) Decrypt(ctx context.Context, uid string, req *kmsservice.DecryptRequest) ([]byte, error) {
ctx, cancel := context.WithTimeout(ctx, g.callTimeout)
defer cancel()
@ -106,7 +107,7 @@ func (g *gRPCService) Decrypt(ctx context.Context, uid string, req *DecryptReque
}
// Encrypt bytes to a string ciphertext.
func (g *gRPCService) Encrypt(ctx context.Context, uid string, plaintext []byte) (*EncryptResponse, error) {
func (g *gRPCService) Encrypt(ctx context.Context, uid string, plaintext []byte) (*kmsservice.EncryptResponse, error) {
ctx, cancel := context.WithTimeout(ctx, g.callTimeout)
defer cancel()
@ -118,7 +119,7 @@ func (g *gRPCService) Encrypt(ctx context.Context, uid string, plaintext []byte)
if err != nil {
return nil, err
}
return &EncryptResponse{
return &kmsservice.EncryptResponse{
Ciphertext: response.Ciphertext,
KeyID: response.KeyId,
Annotations: response.Annotations,
@ -126,7 +127,7 @@ func (g *gRPCService) Encrypt(ctx context.Context, uid string, plaintext []byte)
}
// Status returns the status of the KMSv2 provider.
func (g *gRPCService) Status(ctx context.Context) (*StatusResponse, error) {
func (g *gRPCService) Status(ctx context.Context) (*kmsservice.StatusResponse, error) {
ctx, cancel := context.WithTimeout(ctx, g.callTimeout)
defer cancel()
@ -135,5 +136,5 @@ func (g *gRPCService) Status(ctx context.Context) (*StatusResponse, error) {
if err != nil {
return nil, err
}
return &StatusResponse{Version: response.Version, Healthz: response.Healthz, KeyID: response.KeyId}, nil
return &kmsservice.StatusResponse{Version: response.Version, Healthz: response.Healthz, KeyID: response.KeyId}, nil
}

View File

@ -28,6 +28,7 @@ import (
mock "k8s.io/apiserver/pkg/storage/value/encrypt/envelope/testing/v2alpha1"
"k8s.io/apimachinery/pkg/util/uuid"
kmsservice "k8s.io/kms/service"
)
type testSocket struct {
@ -120,7 +121,7 @@ func TestTimeouts(t *testing.T) {
t.Run(tt.desc, func(t *testing.T) {
t.Parallel()
var (
service Service
service kmsservice.Service
err error
data = []byte("test data")
uid = string(uuid.NewUUID())
@ -293,7 +294,7 @@ func TestGRPCService(t *testing.T) {
keyID := "1"
// Call service to decrypt data.
result, err := service.Decrypt(ctx, uid, &DecryptRequest{Ciphertext: resp.Ciphertext, KeyID: keyID})
result, err := service.Decrypt(ctx, uid, &kmsservice.DecryptRequest{Ciphertext: resp.Ciphertext, KeyID: keyID})
if err != nil {
t.Fatalf("failed when execute decrypt, error: %v", err)
}
@ -342,7 +343,7 @@ func TestGRPCServiceConcurrentAccess(t *testing.T) {
keyID := "1"
// Call service to decrypt data.
result, err := service.Decrypt(ctx, uid, &DecryptRequest{Ciphertext: resp.Ciphertext, KeyID: keyID})
result, err := service.Decrypt(ctx, uid, &kmsservice.DecryptRequest{Ciphertext: resp.Ciphertext, KeyID: keyID})
if err != nil {
t.Errorf("failed when execute decrypt, error: %v", err)
}
@ -356,7 +357,7 @@ func TestGRPCServiceConcurrentAccess(t *testing.T) {
wg.Wait()
}
func destroyService(service Service) {
func destroyService(service kmsservice.Service) {
if service != nil {
s := service.(*gRPCService)
s.connection.Close()