From 772fa0f62fe232f24170e2c43afbd7031bfc160f Mon Sep 17 00:00:00 2001 From: Wu Qiang Date: Tue, 14 Nov 2017 09:05:01 +0000 Subject: [PATCH 1/9] Add gRPC client service for envelope transformer --- .../pkg/storage/value/encrypt/envelope/BUILD | 28 ++- .../value/encrypt/envelope/grpc_service.go | 151 ++++++++++++ .../encrypt/envelope/grpc_service_test.go | 218 +++++++++++++++++ .../envelope/grpc_service_unix_test.go | 73 ++++++ .../value/encrypt/envelope/service.pb.go | 225 ++++++++++++++++++ .../value/encrypt/envelope/service.proto | 29 +++ .../value/encrypt/envelope/testdata/ca.crt | 22 ++ .../encrypt/envelope/testdata/client.crt | 19 ++ .../encrypt/envelope/testdata/client.key | 5 + .../encrypt/envelope/testdata/server.crt | 19 ++ .../encrypt/envelope/testdata/server.key | 5 + 11 files changed, 792 insertions(+), 2 deletions(-) create mode 100644 staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/grpc_service.go create mode 100644 staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/grpc_service_test.go create mode 100644 staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/grpc_service_unix_test.go create mode 100644 staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/service.pb.go create mode 100644 staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/service.proto create mode 100644 staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/testdata/ca.crt create mode 100644 staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/testdata/client.crt create mode 100644 staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/testdata/client.key create mode 100644 staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/testdata/server.crt create mode 100644 staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/testdata/server.key diff --git a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/BUILD b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/BUILD index cb5d4db5948..329b1ff96fe 100644 --- a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/BUILD +++ b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/BUILD @@ -8,22 +8,40 @@ load( go_library( name = "go_default_library", - srcs = ["envelope.go"], + srcs = [ + "envelope.go", + "grpc_service.go", + "service.pb.go", + ], importpath = "k8s.io/apiserver/pkg/storage/value/encrypt/envelope", deps = [ + "//vendor/github.com/golang/protobuf/proto:go_default_library", "//vendor/github.com/hashicorp/golang-lru:go_default_library", + "//vendor/golang.org/x/net/context:go_default_library", + "//vendor/google.golang.org/grpc:go_default_library", + "//vendor/google.golang.org/grpc/credentials:go_default_library", "//vendor/k8s.io/apiserver/pkg/storage/value:go_default_library", ], ) go_test( name = "go_default_test", - srcs = ["envelope_test.go"], + srcs = [ + "envelope_test.go", + "grpc_service_test.go", + "grpc_service_unix_test.go", + ], + data = glob(["testdata/**"]), embed = [":go_default_library"], importpath = "k8s.io/apiserver/pkg/storage/value/encrypt/envelope", deps = [ + "//vendor/golang.org/x/net/context:go_default_library", + "//vendor/golang.org/x/sys/unix:go_default_library", + "//vendor/google.golang.org/grpc:go_default_library", + "//vendor/google.golang.org/grpc/credentials:go_default_library", "//vendor/k8s.io/apiserver/pkg/storage/value:go_default_library", "//vendor/k8s.io/apiserver/pkg/storage/value/encrypt/aes:go_default_library", + "//vendor/k8s.io/client-go/util/cert:go_default_library", ], ) @@ -39,3 +57,9 @@ filegroup( srcs = [":package-srcs"], tags = ["automanaged"], ) + +filegroup( + name = "go_default_library_protos", + srcs = ["service.proto"], + visibility = ["//visibility:public"], +) diff --git a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/grpc_service.go b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/grpc_service.go new file mode 100644 index 00000000000..d6e158dd7e4 --- /dev/null +++ b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/grpc_service.go @@ -0,0 +1,151 @@ +/* +Copyright 2017 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 envelope transforms values for storage at rest using a Envelope provider +package envelope + +import ( + "crypto/tls" + "crypto/x509" + "fmt" + "io/ioutil" + "net" + "net/url" + "time" + + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + + "golang.org/x/net/context" +) + +const ( + // Supportied protocol schema for gRPC. + tcpProtocol = "tcp" + unixProtocol = "unix" + + // Current version for the protocal interface definition. + version = "v1beta1" +) + +type gRPCService struct { + // gRPC client instance + kmsClient KmsServiceClient + connection *grpc.ClientConn +} + +// NewEnvelopeService returns an envelope.Service which use gRPC to communicate the remote KMS provider. +func NewEnvelopeService(endpoint, serverCert, clientCert, clientKey string) (Service, error) { + protocol, addr, err := parseEndpoint(endpoint) + if err != nil { + return nil, err + } + + dialer := func(addr string, timeout time.Duration) (net.Conn, error) { + return net.DialTimeout(protocol, addr, timeout) + } + + // With or without TLS/SSL support + tlsOption, err := getTlsDialOption(serverCert, clientCert, clientKey) + if err != nil { + return nil, err + } + + conn, err := grpc.Dial(addr, tlsOption, grpc.WithDialer(dialer)) + if err != nil { + return nil, fmt.Errorf("connect remote image service %s failed, error: %v", addr, err) + } + + return &gRPCService{kmsClient: NewKmsServiceClient(conn), connection: conn}, nil +} + +// Parse the endpoint to extract schema, host or path. +func parseEndpoint(endpoint string) (string, string, error) { + u, err := url.Parse(endpoint) + if err != nil { + return "", "", fmt.Errorf("invalid kms provider endpoint %q, error: %v", endpoint, err) + } + + switch u.Scheme { + case tcpProtocol: + return tcpProtocol, u.Host, nil + case unixProtocol: + return unixProtocol, u.Path, nil + default: + return "", "", fmt.Errorf("invalid endpoint %q for remote KMS provider", endpoint) + } +} + +// Build the TLS/SSL options for gRPC client. +func getTlsDialOption(serverCert, clientCert, clientKey string) (grpc.DialOption, error) { + // No TLS/SSL support. + if len(serverCert) == 0 && len(clientCert) == 0 && len(clientKey) == 0 { + return grpc.WithInsecure(), nil + } + + // Set the CA that verify the certificate from the gRPC server. + certPool := x509.NewCertPool() + if len(serverCert) > 0 { + ca, err := ioutil.ReadFile(serverCert) + if err != nil { + return nil, fmt.Errorf("kms provider invalid server cert, error: %v", err) + } + if !certPool.AppendCertsFromPEM(ca) { + return nil, fmt.Errorf("can't append server cert for kms provider") + } + } + + // Set client authenticate certificate. + certificates := make([]tls.Certificate, 0, 1) + if len(clientCert) != 0 || len(clientKey) != 0 { + if len(clientCert) == 0 || len(clientKey) == 0 { + return nil, fmt.Errorf("both client cert and key must be provided for kms provider") + } + + cert, err := tls.LoadX509KeyPair(clientCert, clientKey) + if err != nil { + return nil, fmt.Errorf("kms provider invalid client cert or key, error: %v", err) + } + certificates = append(certificates, cert) + } + + tlsConfig := tls.Config{ + Certificates: certificates, + RootCAs: certPool, + } + transportCreds := credentials.NewTLS(&tlsConfig) + return grpc.WithTransportCredentials(transportCreds), nil +} + +// Decrypt a given data string to obtain the original byte data. +func (g *gRPCService) Decrypt(cipher string) ([]byte, error) { + request := &DecryptRequest{Cipher: []byte(cipher), Version: version} + response, err := g.kmsClient.Decrypt(context.Background(), request) + if err != nil { + return nil, err + } + return response.Plain, nil +} + +// Encrypt bytes to a string ciphertext. +func (g *gRPCService) Encrypt(plain []byte) (string, error) { + request := &EncryptRequest{Plain: plain, Version: version} + response, err := g.kmsClient.Encrypt(context.Background(), request) + if err != nil { + return "", err + } + return string(response.Cipher), nil +} diff --git a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/grpc_service_test.go b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/grpc_service_test.go new file mode 100644 index 00000000000..448a6a5a50f --- /dev/null +++ b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/grpc_service_test.go @@ -0,0 +1,218 @@ +/* +Copyright 2017 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 envelope transforms values for storage at rest using a Envelope provider +package envelope + +import ( + "crypto/tls" + "encoding/base64" + "fmt" + "net" + "reflect" + "testing" + + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + + "golang.org/x/net/context" + "k8s.io/client-go/util/cert" +) + +const ( + // Port 0 to select any available port + listenerAddr = "127.0.0.1:0" + + cafile = "testdata/ca.crt" + serverCert = "testdata/server.crt" + serverKey = "testdata/server.key" + clientCert = "testdata/client.crt" + clientKey = "testdata/client.key" +) + +func TestTcpEndpoint(t *testing.T) { + // Start the gRPC server that listens on tcp socket. + listener, err := tcpListner() + if err != nil { + t.Fatal(err) + } + + server := startTestKmsProvider(listener) + defer server.Stop() + + endpoint := tcpProtocol + "://" + listener.Addr().String() + verifyService(t, endpoint, "", "", "") +} + +func TestTlsEndpoint(t *testing.T) { + // Start the gRPC server that listens on tcp socket. + listener, err := tcpListner() + if err != nil { + t.Fatal(err) + } + + tlsOption, err := tlsServerOption() + if err != nil { + t.Fatal(err) + } + + server := startTestKmsProvider(listener, tlsOption) + defer server.Stop() + + // There are 2 TLS case: no auth and client auth. + endpoint := tcpProtocol + "://" + listener.Addr().String() + certConfigs := []struct { + name string + serverCACert string + clientCert string + clientKey string + }{ + {"noAuth", cafile, "", ""}, + {"clientAuth", cafile, clientCert, clientKey}, + } + for _, testCase := range certConfigs { + t.Run(testCase.name, func(t *testing.T) { + verifyService(t, endpoint, testCase.serverCACert, testCase.clientCert, testCase.clientKey) + }) + } +} + +func TestInvalidConfiguration(t *testing.T) { + // Start the gRPC server that listens on tcp socket. + listener, err := tcpListner() + if err != nil { + t.Fatal(err) + } + + tlsOption, err := tlsServerOption() + if err != nil { + t.Fatal(err) + } + + server := startTestKmsProvider(listener, tlsOption) + defer server.Stop() + endpoint := tcpProtocol + "://" + listener.Addr().String() + + invalidConfigs := []struct { + name string + endpoint string + serverCACert string + clientCert string + clientKey string + }{ + {"emptyConfiguration", "", "", "", ""}, + {"invalidEndpoint", "http://localhost:80", "", "", ""}, + {"invalidServerCACert", endpoint, "non-exits.pem", "", ""}, + {"missClientKey", endpoint, cafile, clientCert, ""}, + {"invalidClientCert", endpoint, cafile, "non-exists.pem", clientKey}, + } + + for _, testCase := range invalidConfigs { + t.Run(testCase.name, func(t *testing.T) { + _, err := NewEnvelopeService( + testCase.endpoint, + testCase.serverCACert, + testCase.clientCert, + testCase.clientKey, + ) + if err == nil { + t.Fatalf("should fail to create envelope service for %s.", testCase.name) + } + }) + } +} + +func verifyService(t *testing.T, endpoint, serverCACert, clientCert, clientKey string) { + service, err := NewEnvelopeService(endpoint, serverCACert, clientCert, clientKey) + if err != nil { + t.Fatalf("failed to create envelope service, error: %v", err) + } + defer destroyService(service) + + data := []byte("test data") + cipher, err := service.Encrypt(data) + if err != nil { + t.Fatalf("failed when execute encrypt, error: %v", err) + } + + result, err := service.Decrypt(cipher) + if err != nil { + t.Fatalf("failed when execute decrypt, error: %v", err) + } + + if !reflect.DeepEqual(data, result) { + t.Errorf("expect: %v, but: %v", data, result) + } +} + +func destroyService(service Service) { + gs := service.(*gRPCService) + gs.connection.Close() +} + +func tcpListner() (net.Listener, error) { + listener, err := net.Listen(tcpProtocol, listenerAddr) + if err != nil { + return nil, fmt.Errorf("failed to listen on the tcp address, error: %v", err) + } + + return listener, nil +} + +func startTestKmsProvider(listener net.Listener, options ...grpc.ServerOption) *grpc.Server { + server := grpc.NewServer(options...) + RegisterKmsServiceServer(server, &base64Server{}) + go server.Serve(listener) + return server +} + +func tlsServerOption() (grpc.ServerOption, error) { + certificate, err := tls.LoadX509KeyPair(serverCert, serverKey) + if err != nil { + return nil, fmt.Errorf("bad server cert or key, error: %v", err) + } + + certPool, err := cert.NewPool(cafile) + if err != nil { + return nil, fmt.Errorf("bad ca file, error: %v", err) + } + + tlsConfig := &tls.Config{ + ClientAuth: tls.VerifyClientCertIfGiven, + Certificates: []tls.Certificate{certificate}, + ClientCAs: certPool, + } + return grpc.Creds(credentials.NewTLS(tlsConfig)), nil +} + +// Fake gRPC sever for remote KMS provider. +type base64Server struct{} + +func (b *base64Server) Decrypt(ctx context.Context, request *DecryptRequest) (*DecryptResponse, error) { + buf := make([]byte, base64.StdEncoding.DecodedLen(len(request.Cipher))) + n, err := base64.StdEncoding.Decode(buf, request.Cipher) + if err != nil { + return nil, err + } + + return &DecryptResponse{Plain: buf[:n]}, nil +} + +func (b *base64Server) Encrypt(ctx context.Context, request *EncryptRequest) (*EncryptResponse, error) { + buf := make([]byte, base64.StdEncoding.EncodedLen(len(request.Plain))) + base64.StdEncoding.Encode(buf, request.Plain) + return &EncryptResponse{Cipher: buf}, nil +} diff --git a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/grpc_service_unix_test.go b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/grpc_service_unix_test.go new file mode 100644 index 00000000000..8e3dab0a4ce --- /dev/null +++ b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/grpc_service_unix_test.go @@ -0,0 +1,73 @@ +/* +Copyright 2017 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. +*/ + +// +build !windows + +// Package envelope transforms values for storage at rest using a Envelope provider +package envelope + +import ( + "fmt" + "net" + "os" + "testing" + + "golang.org/x/sys/unix" +) + +const ( + sockFile = "/tmp/kms-provider.sock" +) + +func TestUnixSockEndpoint(t *testing.T) { + // Start the gRPC server that listens on unix socket. + listener, err := unixSockListner() + if err != nil { + t.Fatal(err) + } + + server := startTestKmsProvider(listener) + defer func() { + server.Stop() + if err := cleanSockFile(); err != nil { + t.Fatal(err) + } + }() + + endpoint := unixProtocol + "://" + sockFile + verifyService(t, endpoint, "", "", "") +} + +func unixSockListner() (net.Listener, error) { + if err := cleanSockFile(); err != nil { + return nil, err + } + + listener, err := net.Listen(unixProtocol, sockFile) + if err != nil { + return nil, fmt.Errorf("failed to listen on the unix socket, error: %v", err) + } + + return listener, nil +} + +func cleanSockFile() error { + err := unix.Unlink(sockFile) + if err != nil && !os.IsNotExist(err) { + return fmt.Errorf("failed to delete the socket file, error: %v", err) + } + return nil +} diff --git a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/service.pb.go b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/service.pb.go new file mode 100644 index 00000000000..903d88a7c85 --- /dev/null +++ b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/service.pb.go @@ -0,0 +1,225 @@ +/* +Copyright 2017 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. +*/ + +// Code generated by protoc-gen-go. +// source: service.proto +// DO NOT EDIT! + +/* +Package envelope is a generated protocol buffer package. + +It is generated from these files: + service.proto + +It has these top-level messages: + DecryptRequest + DecryptResponse + EncryptRequest + EncryptResponse +*/ +package envelope + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +import ( + context "golang.org/x/net/context" + grpc "google.golang.org/grpc" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type DecryptRequest struct { + Cipher []byte `protobuf:"bytes,1,opt,name=cipher,proto3" json:"cipher,omitempty"` + // Version of the KMS plugin API, now use “v1beta1” + Version string `protobuf:"bytes,2,opt,name=version" json:"version,omitempty"` +} + +func (m *DecryptRequest) Reset() { *m = DecryptRequest{} } +func (m *DecryptRequest) String() string { return proto.CompactTextString(m) } +func (*DecryptRequest) ProtoMessage() {} +func (*DecryptRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } + +type DecryptResponse struct { + Plain []byte `protobuf:"bytes,1,opt,name=plain,proto3" json:"plain,omitempty"` +} + +func (m *DecryptResponse) Reset() { *m = DecryptResponse{} } +func (m *DecryptResponse) String() string { return proto.CompactTextString(m) } +func (*DecryptResponse) ProtoMessage() {} +func (*DecryptResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } + +type EncryptRequest struct { + Plain []byte `protobuf:"bytes,1,opt,name=plain,proto3" json:"plain,omitempty"` + // Version of the KMS plugin API, now use “v1beta1” + Version string `protobuf:"bytes,2,opt,name=version" json:"version,omitempty"` +} + +func (m *EncryptRequest) Reset() { *m = EncryptRequest{} } +func (m *EncryptRequest) String() string { return proto.CompactTextString(m) } +func (*EncryptRequest) ProtoMessage() {} +func (*EncryptRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } + +type EncryptResponse struct { + Cipher []byte `protobuf:"bytes,1,opt,name=cipher,proto3" json:"cipher,omitempty"` +} + +func (m *EncryptResponse) Reset() { *m = EncryptResponse{} } +func (m *EncryptResponse) String() string { return proto.CompactTextString(m) } +func (*EncryptResponse) ProtoMessage() {} +func (*EncryptResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } + +func init() { + proto.RegisterType((*DecryptRequest)(nil), "envelope.DecryptRequest") + proto.RegisterType((*DecryptResponse)(nil), "envelope.DecryptResponse") + proto.RegisterType((*EncryptRequest)(nil), "envelope.EncryptRequest") + proto.RegisterType((*EncryptResponse)(nil), "envelope.EncryptResponse") +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// Client API for KmsService service + +type KmsServiceClient interface { + Decrypt(ctx context.Context, in *DecryptRequest, opts ...grpc.CallOption) (*DecryptResponse, error) + Encrypt(ctx context.Context, in *EncryptRequest, opts ...grpc.CallOption) (*EncryptResponse, error) +} + +type kmsServiceClient struct { + cc *grpc.ClientConn +} + +func NewKmsServiceClient(cc *grpc.ClientConn) KmsServiceClient { + return &kmsServiceClient{cc} +} + +func (c *kmsServiceClient) Decrypt(ctx context.Context, in *DecryptRequest, opts ...grpc.CallOption) (*DecryptResponse, error) { + out := new(DecryptResponse) + err := grpc.Invoke(ctx, "/envelope.KmsService/Decrypt", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *kmsServiceClient) Encrypt(ctx context.Context, in *EncryptRequest, opts ...grpc.CallOption) (*EncryptResponse, error) { + out := new(EncryptResponse) + err := grpc.Invoke(ctx, "/envelope.KmsService/Encrypt", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// Server API for KmsService service + +type KmsServiceServer interface { + Decrypt(context.Context, *DecryptRequest) (*DecryptResponse, error) + Encrypt(context.Context, *EncryptRequest) (*EncryptResponse, error) +} + +func RegisterKmsServiceServer(s *grpc.Server, srv KmsServiceServer) { + s.RegisterService(&_KmsService_serviceDesc, srv) +} + +func _KmsService_Decrypt_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DecryptRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(KmsServiceServer).Decrypt(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/envelope.KmsService/Decrypt", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(KmsServiceServer).Decrypt(ctx, req.(*DecryptRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _KmsService_Encrypt_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(EncryptRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(KmsServiceServer).Encrypt(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/envelope.KmsService/Encrypt", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(KmsServiceServer).Encrypt(ctx, req.(*EncryptRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _KmsService_serviceDesc = grpc.ServiceDesc{ + ServiceName: "envelope.KmsService", + HandlerType: (*KmsServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Decrypt", + Handler: _KmsService_Decrypt_Handler, + }, + { + MethodName: "Encrypt", + Handler: _KmsService_Encrypt_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "service.proto", +} + +func init() { proto.RegisterFile("service.proto", fileDescriptor0) } + +var fileDescriptor0 = []byte{ + // 209 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x2d, 0x4e, 0x2d, 0x2a, + 0xcb, 0x4c, 0x4e, 0xd5, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x48, 0xcd, 0x2b, 0x4b, 0xcd, + 0xc9, 0x2f, 0x48, 0x55, 0x72, 0xe2, 0xe2, 0x73, 0x49, 0x4d, 0x2e, 0xaa, 0x2c, 0x28, 0x09, 0x4a, + 0x2d, 0x2c, 0x4d, 0x2d, 0x2e, 0x11, 0x12, 0xe3, 0x62, 0x4b, 0xce, 0x2c, 0xc8, 0x48, 0x2d, 0x92, + 0x60, 0x54, 0x60, 0xd4, 0xe0, 0x09, 0x82, 0xf2, 0x84, 0x24, 0xb8, 0xd8, 0xcb, 0x52, 0x8b, 0x8a, + 0x33, 0xf3, 0xf3, 0x24, 0x98, 0x14, 0x18, 0x35, 0x38, 0x83, 0x60, 0x5c, 0x25, 0x75, 0x2e, 0x7e, + 0xb8, 0x19, 0xc5, 0x05, 0xf9, 0x79, 0xc5, 0xa9, 0x42, 0x22, 0x5c, 0xac, 0x05, 0x39, 0x89, 0x99, + 0x79, 0x50, 0x33, 0x20, 0x1c, 0x25, 0x07, 0x2e, 0x3e, 0xd7, 0x3c, 0x14, 0xcb, 0xb0, 0xaa, 0xc3, + 0x63, 0x95, 0x26, 0x17, 0x3f, 0xdc, 0x04, 0xa8, 0x55, 0x38, 0xdc, 0x6b, 0x34, 0x81, 0x91, 0x8b, + 0xcb, 0x3b, 0xb7, 0x38, 0x18, 0xe2, 0x71, 0x21, 0x07, 0x2e, 0x76, 0xa8, 0x23, 0x85, 0x24, 0xf4, + 0x60, 0xde, 0xd7, 0x43, 0xf5, 0xbb, 0x94, 0x24, 0x16, 0x19, 0x88, 0x35, 0x4a, 0x0c, 0x20, 0x13, + 0xa0, 0x76, 0x23, 0x9b, 0x80, 0xea, 0x21, 0x64, 0x13, 0xd0, 0x1c, 0xaa, 0xc4, 0x90, 0xc4, 0x06, + 0x0e, 0x7d, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0xb0, 0xc2, 0xcf, 0x84, 0x8e, 0x01, 0x00, + 0x00, +} diff --git a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/service.proto b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/service.proto new file mode 100644 index 00000000000..64e1210b146 --- /dev/null +++ b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/service.proto @@ -0,0 +1,29 @@ +syntax = "proto3"; + +package envelope; + +service KmsService { + rpc Decrypt(DecryptRequest) returns (DecryptResponse) {} + rpc Encrypt(EncryptRequest) returns (EncryptResponse) {} +} + +message DecryptRequest { + bytes cipher = 1; + // Version of the KMS plugin API, now use “v1beta1” + string version = 2; +} + +message DecryptResponse { + bytes plain = 1; +} + +message EncryptRequest { + bytes plain = 1; + // Version of the KMS plugin API, now use “v1beta1” + string version = 2; +} + +message EncryptResponse { + bytes cipher = 1; +} + diff --git a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/testdata/ca.crt b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/testdata/ca.crt new file mode 100644 index 00000000000..d1218631f6e --- /dev/null +++ b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/testdata/ca.crt @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDujCCAqKgAwIBAgIUASbBmHT/Y+wdxggFudEoKKgLXsYwDQYJKoZIhvcNAQEL +BQAwdTELMAkGA1UEBhMCVVMxFjAUBgNVBAgTDVNhbiBGcmFuY2lzY28xCzAJBgNV +BAcTAkNBMRgwFgYDVQQKEw9NeSBDb21wYW55IE5hbWUxEzARBgNVBAsTCk9yZyBV +bml0IDIxEjAQBgNVBAMTCU15IG93biBDQTAeFw0xNzA3MTcwNTMzMDBaFw0yMjA3 +MTYwNTMzMDBaMHUxCzAJBgNVBAYTAlVTMRYwFAYDVQQIEw1TYW4gRnJhbmNpc2Nv +MQswCQYDVQQHEwJDQTEYMBYGA1UEChMPTXkgQ29tcGFueSBOYW1lMRMwEQYDVQQL +EwpPcmcgVW5pdCAyMRIwEAYDVQQDEwlNeSBvd24gQ0EwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQC4c79AZIRgUjiE4ekjISLYw0nAH7c9FJf6+U22xwLe +X4Yc3uy94Md1lNhYyvNdba6qLLBKqThYCZYsXK2ZPRnmScYHS/edTmzhZ79tSXUA ++R0YJZK00taWyRCZm2tCgXWdWNebrDBwGL+b2P1bButw81CQVYzPQnZiTnnAOUMt +6qbMxGDXRhNydKGx43QtBuRWHS6wjJEjI50dGK8RBWDupBQrEQzaFt9gU3grTPlh +RWvClrM7LU3A1Ymz3Eq6l4tQhcUXSS3JJVhOLrvh4wujJv/tmIzYylrp7gbUvEYn +PW46UZHKrUM8tNthgTnvcychk73+ZZMoWIj5hsne0mTrAgMBAAGjQjBAMA4GA1Ud +DwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBShLj7pyAcfeLfB +l6vyHo5uvY5WnjANBgkqhkiG9w0BAQsFAAOCAQEAUK7jmNOHmTs58f9fIj6hGppt +Lz/l5+C6KA+1P03cdo+KgQb6MnzvKmhGFHD4QM0envHilHBRNO7VWgA7PuO2JtY1 +NwWQfLoyWcft3OXLmJdWcUI9Che/UWFSxCmxC3U+Cb4+4bNq3j+ygt1T6/I9aTTo +/ymS8H+dXF4n69psY591PA8QeUbaQwc5SEWtIont/XWoq+NwXsrNYglPFzGiaoO6 +gF52I3Z0o0fCHtnOIhBDwrOr7oPJy/SEo49WdnxtG5FcN7qNBvFET7/gOI8TxJMr +gTW3G6jSTjBA8sEIhD4k4LOXxWGWwemP6I/LI849/uKd+DoqKjr5Y/BQvcLy+g== +-----END CERTIFICATE----- diff --git a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/testdata/client.crt b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/testdata/client.crt new file mode 100644 index 00000000000..1a01abb51f7 --- /dev/null +++ b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/testdata/client.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDCzCCAfOgAwIBAgIUHqXu3n2P44f2JjHIKPV0m41URRowDQYJKoZIhvcNAQEL +BQAwdTELMAkGA1UEBhMCVVMxFjAUBgNVBAgTDVNhbiBGcmFuY2lzY28xCzAJBgNV +BAcTAkNBMRgwFgYDVQQKEw9NeSBDb21wYW55IE5hbWUxEzARBgNVBAsTCk9yZyBV +bml0IDIxEjAQBgNVBAMTCU15IG93biBDQTAeFw0xNzA3MTcwNTQ1MDBaFw0yMjA3 +MTYwNTQ1MDBaMEYxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMN +U2FuIEZyYW5jaXNjbzESMBAGA1UEAxMJbG9jYWxob3N0MFkwEwYHKoZIzj0CAQYI +KoZIzj0DAQcDQgAE1na/uyZ4Za0+8letub+cQyqoz40NdouSbxcmb/EEv/rtPMmz +A3u+F8LeXt4SI2+ndQbL0DvpFAOBjJejb3jlfKOBjDCBiTAOBgNVHQ8BAf8EBAMC +BaAwEwYDVR0lBAwwCgYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQU +856v+uMt0F4cgO0dk2k6HpaEa+IwHwYDVR0jBBgwFoAUoS4+6cgHH3i3wZer8h6O +br2OVp4wFAYDVR0RBA0wC4IJbG9jYWxob3N0MA0GCSqGSIb3DQEBCwUAA4IBAQBt +5uNxxxhWFCGlGBrVr2J2KA2IJ3thoMSn6lV9/qU2KMBBYneHHE0FG/ubrP9urQhI +KGPwXsfOdS3iuABOBziiuge9iQisHVWQuNEOtbINbdau2ZLsB2BKKAPit1xG+8gn +7leSvyurcpXPc6QuPHCP5hI081y3w+1H4IUDF0qXoi0jYC/BDwl+lk8yHGFQReu2 +33QdhjXr9Wd20XBO8TJ3oQcAezYvb9bJFDgOkUEhSmMVf86YX0QkuphDvuuU3hQC +S4vVpIzM7xoH3xkvXgOMeReLV1df3J3iHyADhUWiS1RNskymGhFmUumlNUPimhUc +E0wqi62pL+kxg1zjXdXY +-----END CERTIFICATE----- diff --git a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/testdata/client.key b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/testdata/client.key new file mode 100644 index 00000000000..da8ab3348f8 --- /dev/null +++ b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/testdata/client.key @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEINjBFDLQH8NJxn/DBF1lOm92fbx2QGkpfWwwADcPE5p7oAoGCCqGSM49 +AwEHoUQDQgAE1na/uyZ4Za0+8letub+cQyqoz40NdouSbxcmb/EEv/rtPMmzA3u+ +F8LeXt4SI2+ndQbL0DvpFAOBjJejb3jlfA== +-----END EC PRIVATE KEY----- diff --git a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/testdata/server.crt b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/testdata/server.crt new file mode 100644 index 00000000000..fdcf3fffa2f --- /dev/null +++ b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/testdata/server.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDETCCAfmgAwIBAgIUU5D4PeHC+zpmc/jwwa2c/6aHPbowDQYJKoZIhvcNAQEL +BQAwdTELMAkGA1UEBhMCVVMxFjAUBgNVBAgTDVNhbiBGcmFuY2lzY28xCzAJBgNV +BAcTAkNBMRgwFgYDVQQKEw9NeSBDb21wYW55IE5hbWUxEzARBgNVBAsTCk9yZyBV +bml0IDIxEjAQBgNVBAMTCU15IG93biBDQTAeFw0xNzA3MTcwNTM3MDBaFw0yMjA3 +MTYwNTM3MDBaMEYxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMN +U2FuIEZyYW5jaXNjbzESMBAGA1UEAxMJbG9jYWxob3N0MFkwEwYHKoZIzj0CAQYI +KoZIzj0DAQcDQgAEd2CnjPbDOHsbR6CcMhzktDsBrRZAaLjpC/9IHtPH+ivDrey8 +jJzZnD+9aLp5E/QG5Rf1tzKDH+oRatQ43mViHKOBkjCBjzAOBgNVHQ8BAf8EBAMC +BaAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQU +rkKlAy9PqK+TrUqApq4BVBSQgNQwHwYDVR0jBBgwFoAUoS4+6cgHH3i3wZer8h6O +br2OVp4wGgYDVR0RBBMwEYIJbG9jYWxob3N0hwR/AAABMA0GCSqGSIb3DQEBCwUA +A4IBAQCikDXkrB4dw8zBrkIA6plgdcgVm1zJbRDhjAVHxHlh/ISPP7Zu9faLmlEN +GC0KK1AmQQciCyoI84VoBQ5WMtyMfbEn0klJ4OOtGwMZtZfgWSD0LX9APIZEU9WH +nvjLLCHkxbq/cf01pAYIlyBhI5vl7/m8b1xVYarKcb2/Homr8guTzRSyJb0Gmeoo +vdiGIhHhvP186OGzOOQVlorZ/WWJTlhXviGJ0QWARthUi+wEHRhJ+STH2VtOrKhb +4tvG0/G9mYK1LOIbZesHtF9C35XThkh/W/rKRWe6/J8pOYh/vFB/aQL73HPvIcpD +tcmR7635hb+42P7raby70UC7nLWf +-----END CERTIFICATE----- diff --git a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/testdata/server.key b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/testdata/server.key new file mode 100644 index 00000000000..fad778e5adc --- /dev/null +++ b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/testdata/server.key @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIN18H0TgTgqfYWVn2BtQym4mUfICD4XcuWE+nhn+fxSeoAoGCCqGSM49 +AwEHoUQDQgAEd2CnjPbDOHsbR6CcMhzktDsBrRZAaLjpC/9IHtPH+ivDrey8jJzZ +nD+9aLp5E/QG5Rf1tzKDH+oRatQ43mViHA== +-----END EC PRIVATE KEY----- From 31fb539f1735debd38e705fcb96a05ea0313c5f5 Mon Sep 17 00:00:00 2001 From: Wu Qiang Date: Tue, 14 Nov 2017 09:05:52 +0000 Subject: [PATCH 2/9] Update kms provider config for gRPC client service --- .../server/options/encryptionconfig/config.go | 41 ++++++++++++++----- .../server/options/encryptionconfig/types.go | 18 ++++++++ 2 files changed, 48 insertions(+), 11 deletions(-) diff --git a/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/config.go b/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/config.go index ad2f0927c6a..c78f3490c6d 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/config.go +++ b/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/config.go @@ -150,18 +150,37 @@ func GetPrefixTransformers(config *ResourceConfig) ([]value.PrefixTransformer, e if found == true { return nil, fmt.Errorf("more than one provider specified in a single element, should split into different list elements") } - f, err := os.Open(provider.KMS.ConfigFile) - if err != nil { - return nil, fmt.Errorf("error opening KMS provider configuration file %q: %v", provider.KMS.ConfigFile, err) - } - defer f.Close() - envelopeService, pluginFound, err := KMSPluginRegistry.getPlugin(provider.KMS.Name, f) - if err != nil { - return nil, fmt.Errorf("could not configure KMS plugin %q, %v", provider.KMS.Name, err) - } - if pluginFound == false { - return nil, fmt.Errorf("KMS plugin %q not found", provider.KMS.Name) + + var envelopeService envelope.Service + remoteConfig := provider.KMS.RemoteServer + if remoteConfig == nil { + // There should be no KMS provider plugins on API server side in future. + f, err := os.Open(provider.KMS.ConfigFile) + if err != nil { + return nil, fmt.Errorf("error opening KMS provider configuration file %q: %v", provider.KMS.ConfigFile, err) + } + defer f.Close() + pluginFound := false + envelopeService, pluginFound, err = KMSPluginRegistry.getPlugin(provider.KMS.Name, f) + if err != nil { + return nil, fmt.Errorf("could not configure KMS plugin %q, %v", provider.KMS.Name, err) + } + if pluginFound == false { + return nil, fmt.Errorf("KMS plugin %q not found", provider.KMS.Name) + } + } else { + // Get gRPC client service with remote config + envelopeService, err = envelope.NewEnvelopeService( + remoteConfig.Endpoint, + remoteConfig.ServerCACert, + remoteConfig.ClientCert, + remoteConfig.ClientKey, + ) + if err != nil { + return nil, fmt.Errorf("could not configure KMS plugin %q, error: %v", provider.KMS.Name, err) + } } + transformer, err = getEnvelopePrefixTransformer(provider.KMS, envelopeService, kmsTransformerPrefixV1) found = true } diff --git a/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/types.go b/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/types.go index 1603e044a31..7f37238d9e4 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/types.go +++ b/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/types.go @@ -83,4 +83,22 @@ type KMSConfig struct { CacheSize int `json:"cachesize,omitempty"` // configfile is the path to the configuration file for the named KMS provider. ConfigFile string `json:"configfile"` + // remoteServer is the configuration for connection gRPC server. + RemoteServer *RemoteServerConfig `json:"remoteServer"` +} + +// RemoteServerConfig contains the connection informations that connect remote +// gRPC server for envelope transformer. +type RemoteServerConfig struct { + // gRPC server listen address, for example tcp://localhost:3735, + // unix:///var/run/kmsprovider.sock + Endpoint string `json:"endpoint"` + + // CACert is the path to a PEM-encoded CA cert file to use to verify the + // gRPC server SSL certificate. + ServerCACert string `json:"serverCACert"` + + // TLS certificate authentication information + ClientCert string `json:"clientCert"` + ClientKey string `json:"clientKey"` } From 16b04d68b1ae180d61ea4ca06d1c8139c25a652f Mon Sep 17 00:00:00 2001 From: Wu Qiang Date: Wed, 15 Nov 2017 11:20:12 +0800 Subject: [PATCH 3/9] Fix verify error and address review comments Signed-off-by: Wu Qiang --- hack/.golint_failures | 1 + .../server/options/encryptionconfig/config.go | 2 +- .../pkg/storage/value/encrypt/envelope/BUILD | 15 ++- .../value/encrypt/envelope/grpc_service.go | 22 +++-- .../encrypt/envelope/grpc_service_test.go | 27 +++--- .../envelope/grpc_service_unix_test.go | 2 +- .../value/encrypt/envelope/v1beta1/BUILD | 33 +++++++ .../envelope/{ => v1beta1}/service.pb.go | 91 +++++++++---------- .../envelope/{ => v1beta1}/service.proto | 4 +- 9 files changed, 117 insertions(+), 80 deletions(-) create mode 100644 staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/v1beta1/BUILD rename staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/{ => v1beta1}/service.pb.go (65%) rename staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/{ => v1beta1}/service.proto (92%) diff --git a/hack/.golint_failures b/hack/.golint_failures index 19c8badcf11..4f14f014fac 100644 --- a/hack/.golint_failures +++ b/hack/.golint_failures @@ -605,6 +605,7 @@ staging/src/k8s.io/apiserver/pkg/storage/storagebackend staging/src/k8s.io/apiserver/pkg/storage/testing staging/src/k8s.io/apiserver/pkg/storage/tests staging/src/k8s.io/apiserver/pkg/storage/value +staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/v1beta1 staging/src/k8s.io/apiserver/pkg/util/feature staging/src/k8s.io/apiserver/pkg/util/flag staging/src/k8s.io/apiserver/pkg/util/proxy diff --git a/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/config.go b/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/config.go index c78f3490c6d..b0c553befcb 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/config.go +++ b/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/config.go @@ -170,7 +170,7 @@ func GetPrefixTransformers(config *ResourceConfig) ([]value.PrefixTransformer, e } } else { // Get gRPC client service with remote config - envelopeService, err = envelope.NewEnvelopeService( + envelopeService, err = envelope.NewGRPCService( remoteConfig.Endpoint, remoteConfig.ServerCACert, remoteConfig.ClientCert, diff --git a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/BUILD b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/BUILD index 329b1ff96fe..0f0e568053b 100644 --- a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/BUILD +++ b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/BUILD @@ -11,16 +11,15 @@ go_library( srcs = [ "envelope.go", "grpc_service.go", - "service.pb.go", ], importpath = "k8s.io/apiserver/pkg/storage/value/encrypt/envelope", deps = [ - "//vendor/github.com/golang/protobuf/proto:go_default_library", "//vendor/github.com/hashicorp/golang-lru:go_default_library", "//vendor/golang.org/x/net/context:go_default_library", "//vendor/google.golang.org/grpc:go_default_library", "//vendor/google.golang.org/grpc/credentials:go_default_library", "//vendor/k8s.io/apiserver/pkg/storage/value:go_default_library", + "//vendor/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/v1beta1:go_default_library", ], ) @@ -41,6 +40,7 @@ go_test( "//vendor/google.golang.org/grpc/credentials:go_default_library", "//vendor/k8s.io/apiserver/pkg/storage/value:go_default_library", "//vendor/k8s.io/apiserver/pkg/storage/value/encrypt/aes:go_default_library", + "//vendor/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/v1beta1:go_default_library", "//vendor/k8s.io/client-go/util/cert:go_default_library", ], ) @@ -54,12 +54,9 @@ filegroup( filegroup( name = "all-srcs", - srcs = [":package-srcs"], + srcs = [ + ":package-srcs", + "//staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/v1beta1:all-srcs", + ], tags = ["automanaged"], ) - -filegroup( - name = "go_default_library_protos", - srcs = ["service.proto"], - visibility = ["//visibility:public"], -) diff --git a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/grpc_service.go b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/grpc_service.go index d6e158dd7e4..17fed2d9afa 100644 --- a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/grpc_service.go +++ b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/grpc_service.go @@ -30,6 +30,8 @@ import ( "google.golang.org/grpc/credentials" "golang.org/x/net/context" + + kmsapi "k8s.io/apiserver/pkg/storage/value/encrypt/envelope/v1beta1" ) const ( @@ -43,12 +45,12 @@ const ( type gRPCService struct { // gRPC client instance - kmsClient KmsServiceClient + kmsClient kmsapi.KMSServiceClient connection *grpc.ClientConn } -// NewEnvelopeService returns an envelope.Service which use gRPC to communicate the remote KMS provider. -func NewEnvelopeService(endpoint, serverCert, clientCert, clientKey string) (Service, error) { +// NewGRPCService returns an envelope.Service which use gRPC to communicate the remote KMS provider. +func NewGRPCService(endpoint, serverCert, clientCert, clientKey string) (Service, error) { protocol, addr, err := parseEndpoint(endpoint) if err != nil { return nil, err @@ -59,7 +61,7 @@ func NewEnvelopeService(endpoint, serverCert, clientCert, clientKey string) (Ser } // With or without TLS/SSL support - tlsOption, err := getTlsDialOption(serverCert, clientCert, clientKey) + tlsOption, err := getTLSDialOption(serverCert, clientCert, clientKey) if err != nil { return nil, err } @@ -69,11 +71,15 @@ func NewEnvelopeService(endpoint, serverCert, clientCert, clientKey string) (Ser return nil, fmt.Errorf("connect remote image service %s failed, error: %v", addr, err) } - return &gRPCService{kmsClient: NewKmsServiceClient(conn), connection: conn}, nil + return &gRPCService{kmsClient: kmsapi.NewKMSServiceClient(conn), connection: conn}, nil } // Parse the endpoint to extract schema, host or path. func parseEndpoint(endpoint string) (string, string, error) { + if len(endpoint) == 0 { + return "", "", fmt.Errorf("remote KMS provider can't use empty string as endpoint") + } + u, err := url.Parse(endpoint) if err != nil { return "", "", fmt.Errorf("invalid kms provider endpoint %q, error: %v", endpoint, err) @@ -90,7 +96,7 @@ func parseEndpoint(endpoint string) (string, string, error) { } // Build the TLS/SSL options for gRPC client. -func getTlsDialOption(serverCert, clientCert, clientKey string) (grpc.DialOption, error) { +func getTLSDialOption(serverCert, clientCert, clientKey string) (grpc.DialOption, error) { // No TLS/SSL support. if len(serverCert) == 0 && len(clientCert) == 0 && len(clientKey) == 0 { return grpc.WithInsecure(), nil @@ -132,7 +138,7 @@ func getTlsDialOption(serverCert, clientCert, clientKey string) (grpc.DialOption // Decrypt a given data string to obtain the original byte data. func (g *gRPCService) Decrypt(cipher string) ([]byte, error) { - request := &DecryptRequest{Cipher: []byte(cipher), Version: version} + request := &kmsapi.DecryptRequest{Cipher: []byte(cipher), Version: version} response, err := g.kmsClient.Decrypt(context.Background(), request) if err != nil { return nil, err @@ -142,7 +148,7 @@ func (g *gRPCService) Decrypt(cipher string) ([]byte, error) { // Encrypt bytes to a string ciphertext. func (g *gRPCService) Encrypt(plain []byte) (string, error) { - request := &EncryptRequest{Plain: plain, Version: version} + request := &kmsapi.EncryptRequest{Plain: plain, Version: version} response, err := g.kmsClient.Encrypt(context.Background(), request) if err != nil { return "", err diff --git a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/grpc_service_test.go b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/grpc_service_test.go index 448a6a5a50f..c4ff79ba204 100644 --- a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/grpc_service_test.go +++ b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/grpc_service_test.go @@ -29,6 +29,7 @@ import ( "google.golang.org/grpc/credentials" "golang.org/x/net/context" + kmsapi "k8s.io/apiserver/pkg/storage/value/encrypt/envelope/v1beta1" "k8s.io/client-go/util/cert" ) @@ -43,21 +44,21 @@ const ( clientKey = "testdata/client.key" ) -func TestTcpEndpoint(t *testing.T) { +func TestTCPEndpoint(t *testing.T) { // Start the gRPC server that listens on tcp socket. listener, err := tcpListner() if err != nil { t.Fatal(err) } - server := startTestKmsProvider(listener) + server := startTestKMSProvider(listener) defer server.Stop() endpoint := tcpProtocol + "://" + listener.Addr().String() verifyService(t, endpoint, "", "", "") } -func TestTlsEndpoint(t *testing.T) { +func TestTLSEndpoint(t *testing.T) { // Start the gRPC server that listens on tcp socket. listener, err := tcpListner() if err != nil { @@ -69,7 +70,7 @@ func TestTlsEndpoint(t *testing.T) { t.Fatal(err) } - server := startTestKmsProvider(listener, tlsOption) + server := startTestKMSProvider(listener, tlsOption) defer server.Stop() // There are 2 TLS case: no auth and client auth. @@ -102,7 +103,7 @@ func TestInvalidConfiguration(t *testing.T) { t.Fatal(err) } - server := startTestKmsProvider(listener, tlsOption) + server := startTestKMSProvider(listener, tlsOption) defer server.Stop() endpoint := tcpProtocol + "://" + listener.Addr().String() @@ -122,7 +123,7 @@ func TestInvalidConfiguration(t *testing.T) { for _, testCase := range invalidConfigs { t.Run(testCase.name, func(t *testing.T) { - _, err := NewEnvelopeService( + _, err := NewGRPCService( testCase.endpoint, testCase.serverCACert, testCase.clientCert, @@ -136,7 +137,7 @@ func TestInvalidConfiguration(t *testing.T) { } func verifyService(t *testing.T, endpoint, serverCACert, clientCert, clientKey string) { - service, err := NewEnvelopeService(endpoint, serverCACert, clientCert, clientKey) + service, err := NewGRPCService(endpoint, serverCACert, clientCert, clientKey) if err != nil { t.Fatalf("failed to create envelope service, error: %v", err) } @@ -172,9 +173,9 @@ func tcpListner() (net.Listener, error) { return listener, nil } -func startTestKmsProvider(listener net.Listener, options ...grpc.ServerOption) *grpc.Server { +func startTestKMSProvider(listener net.Listener, options ...grpc.ServerOption) *grpc.Server { server := grpc.NewServer(options...) - RegisterKmsServiceServer(server, &base64Server{}) + kmsapi.RegisterKMSServiceServer(server, &base64Server{}) go server.Serve(listener) return server } @@ -201,18 +202,18 @@ func tlsServerOption() (grpc.ServerOption, error) { // Fake gRPC sever for remote KMS provider. type base64Server struct{} -func (b *base64Server) Decrypt(ctx context.Context, request *DecryptRequest) (*DecryptResponse, error) { +func (b *base64Server) Decrypt(ctx context.Context, request *kmsapi.DecryptRequest) (*kmsapi.DecryptResponse, error) { buf := make([]byte, base64.StdEncoding.DecodedLen(len(request.Cipher))) n, err := base64.StdEncoding.Decode(buf, request.Cipher) if err != nil { return nil, err } - return &DecryptResponse{Plain: buf[:n]}, nil + return &kmsapi.DecryptResponse{Plain: buf[:n]}, nil } -func (b *base64Server) Encrypt(ctx context.Context, request *EncryptRequest) (*EncryptResponse, error) { +func (b *base64Server) Encrypt(ctx context.Context, request *kmsapi.EncryptRequest) (*kmsapi.EncryptResponse, error) { buf := make([]byte, base64.StdEncoding.EncodedLen(len(request.Plain))) base64.StdEncoding.Encode(buf, request.Plain) - return &EncryptResponse{Cipher: buf}, nil + return &kmsapi.EncryptResponse{Cipher: buf}, nil } diff --git a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/grpc_service_unix_test.go b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/grpc_service_unix_test.go index 8e3dab0a4ce..befcb3e297b 100644 --- a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/grpc_service_unix_test.go +++ b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/grpc_service_unix_test.go @@ -39,7 +39,7 @@ func TestUnixSockEndpoint(t *testing.T) { t.Fatal(err) } - server := startTestKmsProvider(listener) + server := startTestKMSProvider(listener) defer func() { server.Stop() if err := cleanSockFile(); err != nil { diff --git a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/v1beta1/BUILD b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/v1beta1/BUILD new file mode 100644 index 00000000000..d45a85b373f --- /dev/null +++ b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/v1beta1/BUILD @@ -0,0 +1,33 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +filegroup( + name = "go_default_library_protos", + srcs = ["service.proto"], + visibility = ["//visibility:public"], +) + +go_library( + name = "go_default_library", + srcs = ["service.pb.go"], + importpath = "k8s.io/apiserver/pkg/storage/value/encrypt/envelope/v1beta1", + visibility = ["//visibility:public"], + deps = [ + "//vendor/github.com/golang/protobuf/proto:go_default_library", + "//vendor/golang.org/x/net/context:go_default_library", + "//vendor/google.golang.org/grpc:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) diff --git a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/service.pb.go b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/v1beta1/service.pb.go similarity index 65% rename from staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/service.pb.go rename to staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/v1beta1/service.pb.go index 903d88a7c85..e2c13de9798 100644 --- a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/service.pb.go +++ b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/v1beta1/service.pb.go @@ -19,7 +19,7 @@ limitations under the License. // DO NOT EDIT! /* -Package envelope is a generated protocol buffer package. +Package v1beta1 is a generated protocol buffer package. It is generated from these files: service.proto @@ -30,7 +30,7 @@ It has these top-level messages: EncryptRequest EncryptResponse */ -package envelope +package v1beta1 import proto "github.com/golang/protobuf/proto" import fmt "fmt" @@ -93,10 +93,10 @@ func (*EncryptResponse) ProtoMessage() {} func (*EncryptResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } func init() { - proto.RegisterType((*DecryptRequest)(nil), "envelope.DecryptRequest") - proto.RegisterType((*DecryptResponse)(nil), "envelope.DecryptResponse") - proto.RegisterType((*EncryptRequest)(nil), "envelope.EncryptRequest") - proto.RegisterType((*EncryptResponse)(nil), "envelope.EncryptResponse") + proto.RegisterType((*DecryptRequest)(nil), "v1beta1.DecryptRequest") + proto.RegisterType((*DecryptResponse)(nil), "v1beta1.DecryptResponse") + proto.RegisterType((*EncryptRequest)(nil), "v1beta1.EncryptRequest") + proto.RegisterType((*EncryptResponse)(nil), "v1beta1.EncryptResponse") } // Reference imports to suppress errors if they are not otherwise used. @@ -107,97 +107,97 @@ var _ grpc.ClientConn // is compatible with the grpc package it is being compiled against. const _ = grpc.SupportPackageIsVersion4 -// Client API for KmsService service +// Client API for KMSService service -type KmsServiceClient interface { +type KMSServiceClient interface { Decrypt(ctx context.Context, in *DecryptRequest, opts ...grpc.CallOption) (*DecryptResponse, error) Encrypt(ctx context.Context, in *EncryptRequest, opts ...grpc.CallOption) (*EncryptResponse, error) } -type kmsServiceClient struct { +type kMSServiceClient struct { cc *grpc.ClientConn } -func NewKmsServiceClient(cc *grpc.ClientConn) KmsServiceClient { - return &kmsServiceClient{cc} +func NewKMSServiceClient(cc *grpc.ClientConn) KMSServiceClient { + return &kMSServiceClient{cc} } -func (c *kmsServiceClient) Decrypt(ctx context.Context, in *DecryptRequest, opts ...grpc.CallOption) (*DecryptResponse, error) { +func (c *kMSServiceClient) Decrypt(ctx context.Context, in *DecryptRequest, opts ...grpc.CallOption) (*DecryptResponse, error) { out := new(DecryptResponse) - err := grpc.Invoke(ctx, "/envelope.KmsService/Decrypt", in, out, c.cc, opts...) + err := grpc.Invoke(ctx, "/v1beta1.KMSService/Decrypt", in, out, c.cc, opts...) if err != nil { return nil, err } return out, nil } -func (c *kmsServiceClient) Encrypt(ctx context.Context, in *EncryptRequest, opts ...grpc.CallOption) (*EncryptResponse, error) { +func (c *kMSServiceClient) Encrypt(ctx context.Context, in *EncryptRequest, opts ...grpc.CallOption) (*EncryptResponse, error) { out := new(EncryptResponse) - err := grpc.Invoke(ctx, "/envelope.KmsService/Encrypt", in, out, c.cc, opts...) + err := grpc.Invoke(ctx, "/v1beta1.KMSService/Encrypt", in, out, c.cc, opts...) if err != nil { return nil, err } return out, nil } -// Server API for KmsService service +// Server API for KMSService service -type KmsServiceServer interface { +type KMSServiceServer interface { Decrypt(context.Context, *DecryptRequest) (*DecryptResponse, error) Encrypt(context.Context, *EncryptRequest) (*EncryptResponse, error) } -func RegisterKmsServiceServer(s *grpc.Server, srv KmsServiceServer) { - s.RegisterService(&_KmsService_serviceDesc, srv) +func RegisterKMSServiceServer(s *grpc.Server, srv KMSServiceServer) { + s.RegisterService(&_KMSService_serviceDesc, srv) } -func _KmsService_Decrypt_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { +func _KMSService_Decrypt_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(DecryptRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(KmsServiceServer).Decrypt(ctx, in) + return srv.(KMSServiceServer).Decrypt(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/envelope.KmsService/Decrypt", + FullMethod: "/v1beta1.KMSService/Decrypt", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(KmsServiceServer).Decrypt(ctx, req.(*DecryptRequest)) + return srv.(KMSServiceServer).Decrypt(ctx, req.(*DecryptRequest)) } return interceptor(ctx, in, info, handler) } -func _KmsService_Encrypt_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { +func _KMSService_Encrypt_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(EncryptRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(KmsServiceServer).Encrypt(ctx, in) + return srv.(KMSServiceServer).Encrypt(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/envelope.KmsService/Encrypt", + FullMethod: "/v1beta1.KMSService/Encrypt", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(KmsServiceServer).Encrypt(ctx, req.(*EncryptRequest)) + return srv.(KMSServiceServer).Encrypt(ctx, req.(*EncryptRequest)) } return interceptor(ctx, in, info, handler) } -var _KmsService_serviceDesc = grpc.ServiceDesc{ - ServiceName: "envelope.KmsService", - HandlerType: (*KmsServiceServer)(nil), +var _KMSService_serviceDesc = grpc.ServiceDesc{ + ServiceName: "v1beta1.KMSService", + HandlerType: (*KMSServiceServer)(nil), Methods: []grpc.MethodDesc{ { MethodName: "Decrypt", - Handler: _KmsService_Decrypt_Handler, + Handler: _KMSService_Decrypt_Handler, }, { MethodName: "Encrypt", - Handler: _KmsService_Encrypt_Handler, + Handler: _KMSService_Encrypt_Handler, }, }, Streams: []grpc.StreamDesc{}, @@ -207,19 +207,18 @@ var _KmsService_serviceDesc = grpc.ServiceDesc{ func init() { proto.RegisterFile("service.proto", fileDescriptor0) } var fileDescriptor0 = []byte{ - // 209 bytes of a gzipped FileDescriptorProto + // 207 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x2d, 0x4e, 0x2d, 0x2a, - 0xcb, 0x4c, 0x4e, 0xd5, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x48, 0xcd, 0x2b, 0x4b, 0xcd, - 0xc9, 0x2f, 0x48, 0x55, 0x72, 0xe2, 0xe2, 0x73, 0x49, 0x4d, 0x2e, 0xaa, 0x2c, 0x28, 0x09, 0x4a, - 0x2d, 0x2c, 0x4d, 0x2d, 0x2e, 0x11, 0x12, 0xe3, 0x62, 0x4b, 0xce, 0x2c, 0xc8, 0x48, 0x2d, 0x92, - 0x60, 0x54, 0x60, 0xd4, 0xe0, 0x09, 0x82, 0xf2, 0x84, 0x24, 0xb8, 0xd8, 0xcb, 0x52, 0x8b, 0x8a, - 0x33, 0xf3, 0xf3, 0x24, 0x98, 0x14, 0x18, 0x35, 0x38, 0x83, 0x60, 0x5c, 0x25, 0x75, 0x2e, 0x7e, - 0xb8, 0x19, 0xc5, 0x05, 0xf9, 0x79, 0xc5, 0xa9, 0x42, 0x22, 0x5c, 0xac, 0x05, 0x39, 0x89, 0x99, - 0x79, 0x50, 0x33, 0x20, 0x1c, 0x25, 0x07, 0x2e, 0x3e, 0xd7, 0x3c, 0x14, 0xcb, 0xb0, 0xaa, 0xc3, - 0x63, 0x95, 0x26, 0x17, 0x3f, 0xdc, 0x04, 0xa8, 0x55, 0x38, 0xdc, 0x6b, 0x34, 0x81, 0x91, 0x8b, - 0xcb, 0x3b, 0xb7, 0x38, 0x18, 0xe2, 0x71, 0x21, 0x07, 0x2e, 0x76, 0xa8, 0x23, 0x85, 0x24, 0xf4, - 0x60, 0xde, 0xd7, 0x43, 0xf5, 0xbb, 0x94, 0x24, 0x16, 0x19, 0x88, 0x35, 0x4a, 0x0c, 0x20, 0x13, - 0xa0, 0x76, 0x23, 0x9b, 0x80, 0xea, 0x21, 0x64, 0x13, 0xd0, 0x1c, 0xaa, 0xc4, 0x90, 0xc4, 0x06, - 0x0e, 0x7d, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0xb0, 0xc2, 0xcf, 0x84, 0x8e, 0x01, 0x00, - 0x00, + 0xcb, 0x4c, 0x4e, 0xd5, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x2f, 0x33, 0x4c, 0x4a, 0x2d, + 0x49, 0x34, 0x54, 0x72, 0xe2, 0xe2, 0x73, 0x49, 0x4d, 0x2e, 0xaa, 0x2c, 0x28, 0x09, 0x4a, 0x2d, + 0x2c, 0x4d, 0x2d, 0x2e, 0x11, 0x12, 0xe3, 0x62, 0x4b, 0xce, 0x2c, 0xc8, 0x48, 0x2d, 0x92, 0x60, + 0x54, 0x60, 0xd4, 0xe0, 0x09, 0x82, 0xf2, 0x84, 0x24, 0xb8, 0xd8, 0xcb, 0x52, 0x8b, 0x8a, 0x33, + 0xf3, 0xf3, 0x24, 0x98, 0x14, 0x18, 0x35, 0x38, 0x83, 0x60, 0x5c, 0x25, 0x75, 0x2e, 0x7e, 0xb8, + 0x19, 0xc5, 0x05, 0xf9, 0x79, 0xc5, 0xa9, 0x42, 0x22, 0x5c, 0xac, 0x05, 0x39, 0x89, 0x99, 0x79, + 0x50, 0x33, 0x20, 0x1c, 0x25, 0x07, 0x2e, 0x3e, 0xd7, 0x3c, 0x14, 0xcb, 0xb0, 0xaa, 0xc3, 0x63, + 0x95, 0x26, 0x17, 0x3f, 0xdc, 0x04, 0xa8, 0x55, 0x38, 0xdc, 0x6b, 0xd4, 0xc3, 0xc8, 0xc5, 0xe5, + 0xed, 0x1b, 0x1c, 0x0c, 0xf1, 0xb7, 0x90, 0x1d, 0x17, 0x3b, 0xd4, 0x91, 0x42, 0xe2, 0x7a, 0x50, + 0xdf, 0xeb, 0xa1, 0x7a, 0x5d, 0x4a, 0x02, 0x53, 0x02, 0x62, 0x89, 0x12, 0x03, 0x48, 0x3f, 0xd4, + 0x66, 0x24, 0xfd, 0xa8, 0xbe, 0x41, 0xd2, 0x8f, 0xe6, 0x48, 0x25, 0x86, 0x24, 0x36, 0x70, 0xc0, + 0x1b, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff, 0xd2, 0x95, 0x8d, 0x5c, 0x89, 0x01, 0x00, 0x00, } diff --git a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/service.proto b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/v1beta1/service.proto similarity index 92% rename from staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/service.proto rename to staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/v1beta1/service.proto index 64e1210b146..68b5bd0a091 100644 --- a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/service.proto +++ b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/v1beta1/service.proto @@ -1,8 +1,8 @@ syntax = "proto3"; -package envelope; +package v1beta1; -service KmsService { +service KMSService { rpc Decrypt(DecryptRequest) returns (DecryptResponse) {} rpc Encrypt(EncryptRequest) returns (EncryptResponse) {} } From a6368bb04c1100d1dce1c6bf680056882835b395 Mon Sep 17 00:00:00 2001 From: Wu Qiang Date: Mon, 18 Dec 2017 09:29:56 +0000 Subject: [PATCH 4/9] Only support unix socket for kms gRPC, also add Version method --- hack/.golint_failures | 1 - .../server/options/encryptionconfig/config.go | 12 +- .../server/options/encryptionconfig/types.go | 18 +- .../pkg/storage/value/encrypt/envelope/BUILD | 7 +- .../value/encrypt/envelope/grpc_service.go | 104 ++++----- .../encrypt/envelope/grpc_service_test.go | 219 ------------------ .../envelope/grpc_service_unix_test.go | 130 +++++++++-- .../value/encrypt/envelope/testdata/ca.crt | 22 -- .../encrypt/envelope/testdata/client.crt | 19 -- .../encrypt/envelope/testdata/client.key | 5 - .../encrypt/envelope/testdata/server.crt | 19 -- .../encrypt/envelope/testdata/server.key | 5 - .../encrypt/envelope/v1beta1/service.pb.go | 197 +++++++++++++--- .../encrypt/envelope/v1beta1/service.proto | 36 ++- 14 files changed, 360 insertions(+), 434 deletions(-) delete mode 100644 staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/grpc_service_test.go delete mode 100644 staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/testdata/ca.crt delete mode 100644 staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/testdata/client.crt delete mode 100644 staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/testdata/client.key delete mode 100644 staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/testdata/server.crt delete mode 100644 staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/testdata/server.key diff --git a/hack/.golint_failures b/hack/.golint_failures index 4f14f014fac..19c8badcf11 100644 --- a/hack/.golint_failures +++ b/hack/.golint_failures @@ -605,7 +605,6 @@ staging/src/k8s.io/apiserver/pkg/storage/storagebackend staging/src/k8s.io/apiserver/pkg/storage/testing staging/src/k8s.io/apiserver/pkg/storage/tests staging/src/k8s.io/apiserver/pkg/storage/value -staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/v1beta1 staging/src/k8s.io/apiserver/pkg/util/feature staging/src/k8s.io/apiserver/pkg/util/flag staging/src/k8s.io/apiserver/pkg/util/proxy diff --git a/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/config.go b/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/config.go index b0c553befcb..650b8a37c36 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/config.go +++ b/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/config.go @@ -152,8 +152,7 @@ func GetPrefixTransformers(config *ResourceConfig) ([]value.PrefixTransformer, e } var envelopeService envelope.Service - remoteConfig := provider.KMS.RemoteServer - if remoteConfig == nil { + if len(provider.KMS.ConfigFile) > 0 { // There should be no KMS provider plugins on API server side in future. f, err := os.Open(provider.KMS.ConfigFile) if err != nil { @@ -169,13 +168,8 @@ func GetPrefixTransformers(config *ResourceConfig) ([]value.PrefixTransformer, e return nil, fmt.Errorf("KMS plugin %q not found", provider.KMS.Name) } } else { - // Get gRPC client service with remote config - envelopeService, err = envelope.NewGRPCService( - remoteConfig.Endpoint, - remoteConfig.ServerCACert, - remoteConfig.ClientCert, - remoteConfig.ClientKey, - ) + // Get gRPC client service with endpoint. + envelopeService, err = envelope.NewGRPCService(provider.KMS.Endpoint) if err != nil { return nil, fmt.Errorf("could not configure KMS plugin %q, error: %v", provider.KMS.Name, err) } diff --git a/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/types.go b/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/types.go index 7f37238d9e4..02c604ce272 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/types.go +++ b/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/types.go @@ -83,22 +83,6 @@ type KMSConfig struct { CacheSize int `json:"cachesize,omitempty"` // configfile is the path to the configuration file for the named KMS provider. ConfigFile string `json:"configfile"` - // remoteServer is the configuration for connection gRPC server. - RemoteServer *RemoteServerConfig `json:"remoteServer"` -} - -// RemoteServerConfig contains the connection informations that connect remote -// gRPC server for envelope transformer. -type RemoteServerConfig struct { - // gRPC server listen address, for example tcp://localhost:3735, - // unix:///var/run/kmsprovider.sock + // the gRPC server listening address, for example "unix:///var/run/kms-provider.sock". Endpoint string `json:"endpoint"` - - // CACert is the path to a PEM-encoded CA cert file to use to verify the - // gRPC server SSL certificate. - ServerCACert string `json:"serverCACert"` - - // TLS certificate authentication information - ClientCert string `json:"clientCert"` - ClientKey string `json:"clientKey"` } diff --git a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/BUILD b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/BUILD index 0f0e568053b..0984fd2088c 100644 --- a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/BUILD +++ b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/BUILD @@ -14,10 +14,10 @@ go_library( ], importpath = "k8s.io/apiserver/pkg/storage/value/encrypt/envelope", deps = [ + "//vendor/github.com/golang/glog:go_default_library", "//vendor/github.com/hashicorp/golang-lru:go_default_library", "//vendor/golang.org/x/net/context:go_default_library", "//vendor/google.golang.org/grpc:go_default_library", - "//vendor/google.golang.org/grpc/credentials:go_default_library", "//vendor/k8s.io/apiserver/pkg/storage/value:go_default_library", "//vendor/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/v1beta1:go_default_library", ], @@ -27,21 +27,16 @@ go_test( name = "go_default_test", srcs = [ "envelope_test.go", - "grpc_service_test.go", "grpc_service_unix_test.go", ], - data = glob(["testdata/**"]), embed = [":go_default_library"], importpath = "k8s.io/apiserver/pkg/storage/value/encrypt/envelope", deps = [ - "//vendor/golang.org/x/net/context:go_default_library", "//vendor/golang.org/x/sys/unix:go_default_library", "//vendor/google.golang.org/grpc:go_default_library", - "//vendor/google.golang.org/grpc/credentials:go_default_library", "//vendor/k8s.io/apiserver/pkg/storage/value:go_default_library", "//vendor/k8s.io/apiserver/pkg/storage/value/encrypt/aes:go_default_library", "//vendor/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/v1beta1:go_default_library", - "//vendor/k8s.io/client-go/util/cert:go_default_library", ], ) diff --git a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/grpc_service.go b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/grpc_service.go index 17fed2d9afa..8d68a23a3ce 100644 --- a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/grpc_service.go +++ b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/grpc_service.go @@ -18,16 +18,14 @@ limitations under the License. package envelope import ( - "crypto/tls" - "crypto/x509" "fmt" - "io/ioutil" "net" "net/url" "time" + "github.com/golang/glog" + "google.golang.org/grpc" - "google.golang.org/grpc/credentials" "golang.org/x/net/context" @@ -35,14 +33,14 @@ import ( ) const ( - // Supportied protocol schema for gRPC. - tcpProtocol = "tcp" + // Now only supportied unix domain socket. unixProtocol = "unix" // Current version for the protocal interface definition. - version = "v1beta1" + kmsapiVersion = "v1beta1" ) +// The gRPC implementation for envelope.Service. type gRPCService struct { // gRPC client instance kmsClient kmsapi.KMSServiceClient @@ -50,7 +48,9 @@ type gRPCService struct { } // NewGRPCService returns an envelope.Service which use gRPC to communicate the remote KMS provider. -func NewGRPCService(endpoint, serverCert, clientCert, clientKey string) (Service, error) { +func NewGRPCService(endpoint string) (Service, error) { + glog.Infof("Configure KMS provider with endpoint: %s", endpoint) + protocol, addr, err := parseEndpoint(endpoint) if err != nil { return nil, err @@ -60,18 +60,20 @@ func NewGRPCService(endpoint, serverCert, clientCert, clientKey string) (Service return net.DialTimeout(protocol, addr, timeout) } - // With or without TLS/SSL support - tlsOption, err := getTLSDialOption(serverCert, clientCert, clientKey) + connection, err := grpc.Dial(addr, grpc.WithInsecure(), grpc.WithDialer(dialer)) if err != nil { - return nil, err + return nil, fmt.Errorf("connect remote KMS provider %q failed, error: %v", addr, err) } - conn, err := grpc.Dial(addr, tlsOption, grpc.WithDialer(dialer)) + kmsClient := kmsapi.NewKMSServiceClient(connection) + + err = checkAPIVersion(kmsClient) if err != nil { - return nil, fmt.Errorf("connect remote image service %s failed, error: %v", addr, err) + connection.Close() + return nil, fmt.Errorf("failed check version for %q, error: %v", addr, err) } - return &gRPCService{kmsClient: kmsapi.NewKMSServiceClient(conn), connection: conn}, nil + return &gRPCService{kmsClient: kmsClient, connection: connection}, nil } // Parse the endpoint to extract schema, host or path. @@ -82,63 +84,35 @@ func parseEndpoint(endpoint string) (string, string, error) { u, err := url.Parse(endpoint) if err != nil { - return "", "", fmt.Errorf("invalid kms provider endpoint %q, error: %v", endpoint, err) + return "", "", fmt.Errorf("invalid endpoint %q for remote KMS provider, error: %v", endpoint, err) } - switch u.Scheme { - case tcpProtocol: - return tcpProtocol, u.Host, nil - case unixProtocol: - return unixProtocol, u.Path, nil - default: - return "", "", fmt.Errorf("invalid endpoint %q for remote KMS provider", endpoint) + if u.Scheme != unixProtocol { + return "", "", fmt.Errorf("unsupported scheme %q for remote KMS provider", u.Scheme) } + return unixProtocol, u.Path, nil } -// Build the TLS/SSL options for gRPC client. -func getTLSDialOption(serverCert, clientCert, clientKey string) (grpc.DialOption, error) { - // No TLS/SSL support. - if len(serverCert) == 0 && len(clientCert) == 0 && len(clientKey) == 0 { - return grpc.WithInsecure(), nil +// Check the KMS provider API version. +// Only matching kubeRuntimeAPIVersion is supported now. +func checkAPIVersion(kmsClient kmsapi.KMSServiceClient) error { + request := &kmsapi.VersionRequest{Version: kmsapiVersion} + response, err := kmsClient.Version(context.Background(), request) + if err != nil { + return fmt.Errorf("failed get version from remote KMS provider: %v", err) + } + if response.Version != kmsapiVersion { + return fmt.Errorf("KMS provider api version %s is not supported, only %s is supported now", + response.Version, kmsapiVersion) } - // Set the CA that verify the certificate from the gRPC server. - certPool := x509.NewCertPool() - if len(serverCert) > 0 { - ca, err := ioutil.ReadFile(serverCert) - if err != nil { - return nil, fmt.Errorf("kms provider invalid server cert, error: %v", err) - } - if !certPool.AppendCertsFromPEM(ca) { - return nil, fmt.Errorf("can't append server cert for kms provider") - } - } - - // Set client authenticate certificate. - certificates := make([]tls.Certificate, 0, 1) - if len(clientCert) != 0 || len(clientKey) != 0 { - if len(clientCert) == 0 || len(clientKey) == 0 { - return nil, fmt.Errorf("both client cert and key must be provided for kms provider") - } - - cert, err := tls.LoadX509KeyPair(clientCert, clientKey) - if err != nil { - return nil, fmt.Errorf("kms provider invalid client cert or key, error: %v", err) - } - certificates = append(certificates, cert) - } - - tlsConfig := tls.Config{ - Certificates: certificates, - RootCAs: certPool, - } - transportCreds := credentials.NewTLS(&tlsConfig) - return grpc.WithTransportCredentials(transportCreds), nil + glog.Infof("KMS provider %s initialized, version: %s", response.RuntimeName, response.RuntimeVersion) + return nil } // Decrypt a given data string to obtain the original byte data. -func (g *gRPCService) Decrypt(cipher string) ([]byte, error) { - request := &kmsapi.DecryptRequest{Cipher: []byte(cipher), Version: version} +func (g *gRPCService) Decrypt(cipher []byte) ([]byte, error) { + request := &kmsapi.DecryptRequest{Cipher: cipher, Version: kmsapiVersion} response, err := g.kmsClient.Decrypt(context.Background(), request) if err != nil { return nil, err @@ -147,11 +121,11 @@ func (g *gRPCService) Decrypt(cipher string) ([]byte, error) { } // Encrypt bytes to a string ciphertext. -func (g *gRPCService) Encrypt(plain []byte) (string, error) { - request := &kmsapi.EncryptRequest{Plain: plain, Version: version} +func (g *gRPCService) Encrypt(plain []byte) ([]byte, error) { + request := &kmsapi.EncryptRequest{Plain: plain, Version: kmsapiVersion} response, err := g.kmsClient.Encrypt(context.Background(), request) if err != nil { - return "", err + return nil, err } - return string(response.Cipher), nil + return response.Cipher, nil } diff --git a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/grpc_service_test.go b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/grpc_service_test.go deleted file mode 100644 index c4ff79ba204..00000000000 --- a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/grpc_service_test.go +++ /dev/null @@ -1,219 +0,0 @@ -/* -Copyright 2017 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 envelope transforms values for storage at rest using a Envelope provider -package envelope - -import ( - "crypto/tls" - "encoding/base64" - "fmt" - "net" - "reflect" - "testing" - - "google.golang.org/grpc" - "google.golang.org/grpc/credentials" - - "golang.org/x/net/context" - kmsapi "k8s.io/apiserver/pkg/storage/value/encrypt/envelope/v1beta1" - "k8s.io/client-go/util/cert" -) - -const ( - // Port 0 to select any available port - listenerAddr = "127.0.0.1:0" - - cafile = "testdata/ca.crt" - serverCert = "testdata/server.crt" - serverKey = "testdata/server.key" - clientCert = "testdata/client.crt" - clientKey = "testdata/client.key" -) - -func TestTCPEndpoint(t *testing.T) { - // Start the gRPC server that listens on tcp socket. - listener, err := tcpListner() - if err != nil { - t.Fatal(err) - } - - server := startTestKMSProvider(listener) - defer server.Stop() - - endpoint := tcpProtocol + "://" + listener.Addr().String() - verifyService(t, endpoint, "", "", "") -} - -func TestTLSEndpoint(t *testing.T) { - // Start the gRPC server that listens on tcp socket. - listener, err := tcpListner() - if err != nil { - t.Fatal(err) - } - - tlsOption, err := tlsServerOption() - if err != nil { - t.Fatal(err) - } - - server := startTestKMSProvider(listener, tlsOption) - defer server.Stop() - - // There are 2 TLS case: no auth and client auth. - endpoint := tcpProtocol + "://" + listener.Addr().String() - certConfigs := []struct { - name string - serverCACert string - clientCert string - clientKey string - }{ - {"noAuth", cafile, "", ""}, - {"clientAuth", cafile, clientCert, clientKey}, - } - for _, testCase := range certConfigs { - t.Run(testCase.name, func(t *testing.T) { - verifyService(t, endpoint, testCase.serverCACert, testCase.clientCert, testCase.clientKey) - }) - } -} - -func TestInvalidConfiguration(t *testing.T) { - // Start the gRPC server that listens on tcp socket. - listener, err := tcpListner() - if err != nil { - t.Fatal(err) - } - - tlsOption, err := tlsServerOption() - if err != nil { - t.Fatal(err) - } - - server := startTestKMSProvider(listener, tlsOption) - defer server.Stop() - endpoint := tcpProtocol + "://" + listener.Addr().String() - - invalidConfigs := []struct { - name string - endpoint string - serverCACert string - clientCert string - clientKey string - }{ - {"emptyConfiguration", "", "", "", ""}, - {"invalidEndpoint", "http://localhost:80", "", "", ""}, - {"invalidServerCACert", endpoint, "non-exits.pem", "", ""}, - {"missClientKey", endpoint, cafile, clientCert, ""}, - {"invalidClientCert", endpoint, cafile, "non-exists.pem", clientKey}, - } - - for _, testCase := range invalidConfigs { - t.Run(testCase.name, func(t *testing.T) { - _, err := NewGRPCService( - testCase.endpoint, - testCase.serverCACert, - testCase.clientCert, - testCase.clientKey, - ) - if err == nil { - t.Fatalf("should fail to create envelope service for %s.", testCase.name) - } - }) - } -} - -func verifyService(t *testing.T, endpoint, serverCACert, clientCert, clientKey string) { - service, err := NewGRPCService(endpoint, serverCACert, clientCert, clientKey) - if err != nil { - t.Fatalf("failed to create envelope service, error: %v", err) - } - defer destroyService(service) - - data := []byte("test data") - cipher, err := service.Encrypt(data) - if err != nil { - t.Fatalf("failed when execute encrypt, error: %v", err) - } - - result, err := service.Decrypt(cipher) - if err != nil { - t.Fatalf("failed when execute decrypt, error: %v", err) - } - - if !reflect.DeepEqual(data, result) { - t.Errorf("expect: %v, but: %v", data, result) - } -} - -func destroyService(service Service) { - gs := service.(*gRPCService) - gs.connection.Close() -} - -func tcpListner() (net.Listener, error) { - listener, err := net.Listen(tcpProtocol, listenerAddr) - if err != nil { - return nil, fmt.Errorf("failed to listen on the tcp address, error: %v", err) - } - - return listener, nil -} - -func startTestKMSProvider(listener net.Listener, options ...grpc.ServerOption) *grpc.Server { - server := grpc.NewServer(options...) - kmsapi.RegisterKMSServiceServer(server, &base64Server{}) - go server.Serve(listener) - return server -} - -func tlsServerOption() (grpc.ServerOption, error) { - certificate, err := tls.LoadX509KeyPair(serverCert, serverKey) - if err != nil { - return nil, fmt.Errorf("bad server cert or key, error: %v", err) - } - - certPool, err := cert.NewPool(cafile) - if err != nil { - return nil, fmt.Errorf("bad ca file, error: %v", err) - } - - tlsConfig := &tls.Config{ - ClientAuth: tls.VerifyClientCertIfGiven, - Certificates: []tls.Certificate{certificate}, - ClientCAs: certPool, - } - return grpc.Creds(credentials.NewTLS(tlsConfig)), nil -} - -// Fake gRPC sever for remote KMS provider. -type base64Server struct{} - -func (b *base64Server) Decrypt(ctx context.Context, request *kmsapi.DecryptRequest) (*kmsapi.DecryptResponse, error) { - buf := make([]byte, base64.StdEncoding.DecodedLen(len(request.Cipher))) - n, err := base64.StdEncoding.Decode(buf, request.Cipher) - if err != nil { - return nil, err - } - - return &kmsapi.DecryptResponse{Plain: buf[:n]}, nil -} - -func (b *base64Server) Encrypt(ctx context.Context, request *kmsapi.EncryptRequest) (*kmsapi.EncryptResponse, error) { - buf := make([]byte, base64.StdEncoding.EncodedLen(len(request.Plain))) - base64.StdEncoding.Encode(buf, request.Plain) - return &kmsapi.EncryptResponse{Cipher: buf}, nil -} diff --git a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/grpc_service_unix_test.go b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/grpc_service_unix_test.go index befcb3e297b..500078cb252 100644 --- a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/grpc_service_unix_test.go +++ b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/grpc_service_unix_test.go @@ -20,38 +20,100 @@ limitations under the License. package envelope import ( + "context" + "encoding/base64" "fmt" "net" "os" + "reflect" "testing" + "google.golang.org/grpc" + "golang.org/x/sys/unix" + + kmsapi "k8s.io/apiserver/pkg/storage/value/encrypt/envelope/v1beta1" ) const ( sockFile = "/tmp/kms-provider.sock" ) -func TestUnixSockEndpoint(t *testing.T) { - // Start the gRPC server that listens on unix socket. - listener, err := unixSockListner() +// Normal encryption and decryption operation. +func TestGRPCService(t *testing.T) { + // Start a test gRPC server. + server, err := startTestKMSProvider() if err != nil { - t.Fatal(err) + t.Fatalf("failed to start test KMS provider server, error: %v", err) + } + defer stopTestKMSProvider(server) + + // Create the gRPC client service. + endpoint := unixProtocol + "://" + sockFile + service, err := NewGRPCService(endpoint) + if err != nil { + t.Fatalf("failed to create envelope service, error: %v", err) + } + defer destroyService(service) + + // Call service to encrypt data. + data := []byte("test data") + cipher, err := service.Encrypt(data) + if err != nil { + t.Fatalf("failed when execute encrypt, error: %v", err) } - server := startTestKMSProvider(listener) - defer func() { - server.Stop() - if err := cleanSockFile(); err != nil { - t.Fatal(err) - } - }() + // Call service to decrypt data. + result, err := service.Decrypt(cipher) + if err != nil { + t.Fatalf("failed when execute decrypt, error: %v", err) + } - endpoint := unixProtocol + "://" + sockFile - verifyService(t, endpoint, "", "", "") + if !reflect.DeepEqual(data, result) { + t.Errorf("expect: %v, but: %v", data, result) + } } -func unixSockListner() (net.Listener, error) { +func destroyService(service Service) { + s := service.(*gRPCService) + s.connection.Close() +} + +// Test all those invalid configuration for KMS provider. +func TestInvalidConfiguration(t *testing.T) { + // Start a test gRPC server. + server, err := startTestKMSProvider() + if err != nil { + t.Fatalf("failed to start test KMS provider server, error: %v", err) + } + defer stopTestKMSProvider(server) + + invalidConfigs := []struct { + name string + apiVersion string + endpoint string + }{ + {"emptyConfiguration", kmsapiVersion, ""}, + {"invalidScheme", kmsapiVersion, "tcp://localhost:6060"}, + {"unavailableEndpoint", kmsapiVersion, unixProtocol + "://" + sockFile + ".nonexist"}, + {"invalidAPIVersion", "invalidVersion", unixProtocol + "://" + sockFile}, + } + + for _, testCase := range invalidConfigs { + t.Run(testCase.name, func(t *testing.T) { + setAPIVersion(testCase.apiVersion) + defer setAPIVersion(kmsapiVersion) + + _, err := NewGRPCService(testCase.endpoint) + if err == nil { + t.Fatalf("should fail to create envelope service for %s.", testCase.name) + } + }) + } +} + +// Start the gRPC server that listens on unix socket. +func startTestKMSProvider() (*grpc.Server, error) { if err := cleanSockFile(); err != nil { return nil, err } @@ -61,7 +123,15 @@ func unixSockListner() (net.Listener, error) { return nil, fmt.Errorf("failed to listen on the unix socket, error: %v", err) } - return listener, nil + server := grpc.NewServer() + kmsapi.RegisterKMSServiceServer(server, &base64Server{}) + go server.Serve(listener) + return server, nil +} + +func stopTestKMSProvider(server *grpc.Server) { + server.Stop() + cleanSockFile() } func cleanSockFile() error { @@ -71,3 +141,33 @@ func cleanSockFile() error { } return nil } + +// Fake gRPC sever for remote KMS provider. +// Use base64 to simulate encrypt and decrypt. +type base64Server struct{} + +var testProviderAPIVersion = kmsapiVersion + +func setAPIVersion(apiVersion string) { + testProviderAPIVersion = apiVersion +} + +func (s *base64Server) Version(ctx context.Context, request *kmsapi.VersionRequest) (*kmsapi.VersionResponse, error) { + return &kmsapi.VersionResponse{Version: testProviderAPIVersion, RuntimeName: "testKMS", RuntimeVersion: "0.0.1"}, nil +} + +func (s *base64Server) Decrypt(ctx context.Context, request *kmsapi.DecryptRequest) (*kmsapi.DecryptResponse, error) { + buf := make([]byte, base64.StdEncoding.DecodedLen(len(request.Cipher))) + n, err := base64.StdEncoding.Decode(buf, request.Cipher) + if err != nil { + return nil, err + } + + return &kmsapi.DecryptResponse{Plain: buf[:n]}, nil +} + +func (s *base64Server) Encrypt(ctx context.Context, request *kmsapi.EncryptRequest) (*kmsapi.EncryptResponse, error) { + buf := make([]byte, base64.StdEncoding.EncodedLen(len(request.Plain))) + base64.StdEncoding.Encode(buf, request.Plain) + return &kmsapi.EncryptResponse{Cipher: buf}, nil +} diff --git a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/testdata/ca.crt b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/testdata/ca.crt deleted file mode 100644 index d1218631f6e..00000000000 --- a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/testdata/ca.crt +++ /dev/null @@ -1,22 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDujCCAqKgAwIBAgIUASbBmHT/Y+wdxggFudEoKKgLXsYwDQYJKoZIhvcNAQEL -BQAwdTELMAkGA1UEBhMCVVMxFjAUBgNVBAgTDVNhbiBGcmFuY2lzY28xCzAJBgNV -BAcTAkNBMRgwFgYDVQQKEw9NeSBDb21wYW55IE5hbWUxEzARBgNVBAsTCk9yZyBV -bml0IDIxEjAQBgNVBAMTCU15IG93biBDQTAeFw0xNzA3MTcwNTMzMDBaFw0yMjA3 -MTYwNTMzMDBaMHUxCzAJBgNVBAYTAlVTMRYwFAYDVQQIEw1TYW4gRnJhbmNpc2Nv -MQswCQYDVQQHEwJDQTEYMBYGA1UEChMPTXkgQ29tcGFueSBOYW1lMRMwEQYDVQQL -EwpPcmcgVW5pdCAyMRIwEAYDVQQDEwlNeSBvd24gQ0EwggEiMA0GCSqGSIb3DQEB -AQUAA4IBDwAwggEKAoIBAQC4c79AZIRgUjiE4ekjISLYw0nAH7c9FJf6+U22xwLe -X4Yc3uy94Md1lNhYyvNdba6qLLBKqThYCZYsXK2ZPRnmScYHS/edTmzhZ79tSXUA -+R0YJZK00taWyRCZm2tCgXWdWNebrDBwGL+b2P1bButw81CQVYzPQnZiTnnAOUMt -6qbMxGDXRhNydKGx43QtBuRWHS6wjJEjI50dGK8RBWDupBQrEQzaFt9gU3grTPlh -RWvClrM7LU3A1Ymz3Eq6l4tQhcUXSS3JJVhOLrvh4wujJv/tmIzYylrp7gbUvEYn -PW46UZHKrUM8tNthgTnvcychk73+ZZMoWIj5hsne0mTrAgMBAAGjQjBAMA4GA1Ud -DwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBShLj7pyAcfeLfB -l6vyHo5uvY5WnjANBgkqhkiG9w0BAQsFAAOCAQEAUK7jmNOHmTs58f9fIj6hGppt -Lz/l5+C6KA+1P03cdo+KgQb6MnzvKmhGFHD4QM0envHilHBRNO7VWgA7PuO2JtY1 -NwWQfLoyWcft3OXLmJdWcUI9Che/UWFSxCmxC3U+Cb4+4bNq3j+ygt1T6/I9aTTo -/ymS8H+dXF4n69psY591PA8QeUbaQwc5SEWtIont/XWoq+NwXsrNYglPFzGiaoO6 -gF52I3Z0o0fCHtnOIhBDwrOr7oPJy/SEo49WdnxtG5FcN7qNBvFET7/gOI8TxJMr -gTW3G6jSTjBA8sEIhD4k4LOXxWGWwemP6I/LI849/uKd+DoqKjr5Y/BQvcLy+g== ------END CERTIFICATE----- diff --git a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/testdata/client.crt b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/testdata/client.crt deleted file mode 100644 index 1a01abb51f7..00000000000 --- a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/testdata/client.crt +++ /dev/null @@ -1,19 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDCzCCAfOgAwIBAgIUHqXu3n2P44f2JjHIKPV0m41URRowDQYJKoZIhvcNAQEL -BQAwdTELMAkGA1UEBhMCVVMxFjAUBgNVBAgTDVNhbiBGcmFuY2lzY28xCzAJBgNV -BAcTAkNBMRgwFgYDVQQKEw9NeSBDb21wYW55IE5hbWUxEzARBgNVBAsTCk9yZyBV -bml0IDIxEjAQBgNVBAMTCU15IG93biBDQTAeFw0xNzA3MTcwNTQ1MDBaFw0yMjA3 -MTYwNTQ1MDBaMEYxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMN -U2FuIEZyYW5jaXNjbzESMBAGA1UEAxMJbG9jYWxob3N0MFkwEwYHKoZIzj0CAQYI -KoZIzj0DAQcDQgAE1na/uyZ4Za0+8letub+cQyqoz40NdouSbxcmb/EEv/rtPMmz -A3u+F8LeXt4SI2+ndQbL0DvpFAOBjJejb3jlfKOBjDCBiTAOBgNVHQ8BAf8EBAMC -BaAwEwYDVR0lBAwwCgYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQU -856v+uMt0F4cgO0dk2k6HpaEa+IwHwYDVR0jBBgwFoAUoS4+6cgHH3i3wZer8h6O -br2OVp4wFAYDVR0RBA0wC4IJbG9jYWxob3N0MA0GCSqGSIb3DQEBCwUAA4IBAQBt -5uNxxxhWFCGlGBrVr2J2KA2IJ3thoMSn6lV9/qU2KMBBYneHHE0FG/ubrP9urQhI -KGPwXsfOdS3iuABOBziiuge9iQisHVWQuNEOtbINbdau2ZLsB2BKKAPit1xG+8gn -7leSvyurcpXPc6QuPHCP5hI081y3w+1H4IUDF0qXoi0jYC/BDwl+lk8yHGFQReu2 -33QdhjXr9Wd20XBO8TJ3oQcAezYvb9bJFDgOkUEhSmMVf86YX0QkuphDvuuU3hQC -S4vVpIzM7xoH3xkvXgOMeReLV1df3J3iHyADhUWiS1RNskymGhFmUumlNUPimhUc -E0wqi62pL+kxg1zjXdXY ------END CERTIFICATE----- diff --git a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/testdata/client.key b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/testdata/client.key deleted file mode 100644 index da8ab3348f8..00000000000 --- a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/testdata/client.key +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN EC PRIVATE KEY----- -MHcCAQEEINjBFDLQH8NJxn/DBF1lOm92fbx2QGkpfWwwADcPE5p7oAoGCCqGSM49 -AwEHoUQDQgAE1na/uyZ4Za0+8letub+cQyqoz40NdouSbxcmb/EEv/rtPMmzA3u+ -F8LeXt4SI2+ndQbL0DvpFAOBjJejb3jlfA== ------END EC PRIVATE KEY----- diff --git a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/testdata/server.crt b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/testdata/server.crt deleted file mode 100644 index fdcf3fffa2f..00000000000 --- a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/testdata/server.crt +++ /dev/null @@ -1,19 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDETCCAfmgAwIBAgIUU5D4PeHC+zpmc/jwwa2c/6aHPbowDQYJKoZIhvcNAQEL -BQAwdTELMAkGA1UEBhMCVVMxFjAUBgNVBAgTDVNhbiBGcmFuY2lzY28xCzAJBgNV -BAcTAkNBMRgwFgYDVQQKEw9NeSBDb21wYW55IE5hbWUxEzARBgNVBAsTCk9yZyBV -bml0IDIxEjAQBgNVBAMTCU15IG93biBDQTAeFw0xNzA3MTcwNTM3MDBaFw0yMjA3 -MTYwNTM3MDBaMEYxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMN -U2FuIEZyYW5jaXNjbzESMBAGA1UEAxMJbG9jYWxob3N0MFkwEwYHKoZIzj0CAQYI -KoZIzj0DAQcDQgAEd2CnjPbDOHsbR6CcMhzktDsBrRZAaLjpC/9IHtPH+ivDrey8 -jJzZnD+9aLp5E/QG5Rf1tzKDH+oRatQ43mViHKOBkjCBjzAOBgNVHQ8BAf8EBAMC -BaAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQU -rkKlAy9PqK+TrUqApq4BVBSQgNQwHwYDVR0jBBgwFoAUoS4+6cgHH3i3wZer8h6O -br2OVp4wGgYDVR0RBBMwEYIJbG9jYWxob3N0hwR/AAABMA0GCSqGSIb3DQEBCwUA -A4IBAQCikDXkrB4dw8zBrkIA6plgdcgVm1zJbRDhjAVHxHlh/ISPP7Zu9faLmlEN -GC0KK1AmQQciCyoI84VoBQ5WMtyMfbEn0klJ4OOtGwMZtZfgWSD0LX9APIZEU9WH -nvjLLCHkxbq/cf01pAYIlyBhI5vl7/m8b1xVYarKcb2/Homr8guTzRSyJb0Gmeoo -vdiGIhHhvP186OGzOOQVlorZ/WWJTlhXviGJ0QWARthUi+wEHRhJ+STH2VtOrKhb -4tvG0/G9mYK1LOIbZesHtF9C35XThkh/W/rKRWe6/J8pOYh/vFB/aQL73HPvIcpD -tcmR7635hb+42P7raby70UC7nLWf ------END CERTIFICATE----- diff --git a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/testdata/server.key b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/testdata/server.key deleted file mode 100644 index fad778e5adc..00000000000 --- a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/testdata/server.key +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN EC PRIVATE KEY----- -MHcCAQEEIN18H0TgTgqfYWVn2BtQym4mUfICD4XcuWE+nhn+fxSeoAoGCCqGSM49 -AwEHoUQDQgAEd2CnjPbDOHsbR6CcMhzktDsBrRZAaLjpC/9IHtPH+ivDrey8jJzZ -nD+9aLp5E/QG5Rf1tzKDH+oRatQ43mViHA== ------END EC PRIVATE KEY----- diff --git a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/v1beta1/service.pb.go b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/v1beta1/service.pb.go index e2c13de9798..118d2e72faa 100644 --- a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/v1beta1/service.pb.go +++ b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/v1beta1/service.pb.go @@ -14,9 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -// Code generated by protoc-gen-go. +// Code generated by protoc-gen-go. DO NOT EDIT. // source: service.proto -// DO NOT EDIT! /* Package v1beta1 is a generated protocol buffer package. @@ -25,6 +24,8 @@ It is generated from these files: service.proto It has these top-level messages: + VersionRequest + VersionResponse DecryptRequest DecryptResponse EncryptRequest @@ -52,47 +53,147 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package +type VersionRequest struct { + // Version of the KMS plugin API. + Version string `protobuf:"bytes,1,opt,name=version" json:"version,omitempty"` +} + +func (m *VersionRequest) Reset() { *m = VersionRequest{} } +func (m *VersionRequest) String() string { return proto.CompactTextString(m) } +func (*VersionRequest) ProtoMessage() {} +func (*VersionRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } + +func (m *VersionRequest) GetVersion() string { + if m != nil { + return m.Version + } + return "" +} + +type VersionResponse struct { + // Version of the KMS plugin API. + Version string `protobuf:"bytes,1,opt,name=version" json:"version,omitempty"` + // Name of the KMS provider. + RuntimeName string `protobuf:"bytes,2,opt,name=runtime_name,json=runtimeName" json:"runtime_name,omitempty"` + // Version of the KMS provider. The string must be semver-compatible. + RuntimeVersion string `protobuf:"bytes,3,opt,name=runtime_version,json=runtimeVersion" json:"runtime_version,omitempty"` +} + +func (m *VersionResponse) Reset() { *m = VersionResponse{} } +func (m *VersionResponse) String() string { return proto.CompactTextString(m) } +func (*VersionResponse) ProtoMessage() {} +func (*VersionResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } + +func (m *VersionResponse) GetVersion() string { + if m != nil { + return m.Version + } + return "" +} + +func (m *VersionResponse) GetRuntimeName() string { + if m != nil { + return m.RuntimeName + } + return "" +} + +func (m *VersionResponse) GetRuntimeVersion() string { + if m != nil { + return m.RuntimeVersion + } + return "" +} + type DecryptRequest struct { - Cipher []byte `protobuf:"bytes,1,opt,name=cipher,proto3" json:"cipher,omitempty"` - // Version of the KMS plugin API, now use “v1beta1” - Version string `protobuf:"bytes,2,opt,name=version" json:"version,omitempty"` + // Version of the KMS plugin API. + Version string `protobuf:"bytes,1,opt,name=version" json:"version,omitempty"` + // The data to be decrypted. + Cipher []byte `protobuf:"bytes,2,opt,name=cipher,proto3" json:"cipher,omitempty"` } func (m *DecryptRequest) Reset() { *m = DecryptRequest{} } func (m *DecryptRequest) String() string { return proto.CompactTextString(m) } func (*DecryptRequest) ProtoMessage() {} -func (*DecryptRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } +func (*DecryptRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } + +func (m *DecryptRequest) GetVersion() string { + if m != nil { + return m.Version + } + return "" +} + +func (m *DecryptRequest) GetCipher() []byte { + if m != nil { + return m.Cipher + } + return nil +} type DecryptResponse struct { + // The decrypted data. Plain []byte `protobuf:"bytes,1,opt,name=plain,proto3" json:"plain,omitempty"` } func (m *DecryptResponse) Reset() { *m = DecryptResponse{} } func (m *DecryptResponse) String() string { return proto.CompactTextString(m) } func (*DecryptResponse) ProtoMessage() {} -func (*DecryptResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } +func (*DecryptResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } + +func (m *DecryptResponse) GetPlain() []byte { + if m != nil { + return m.Plain + } + return nil +} type EncryptRequest struct { - Plain []byte `protobuf:"bytes,1,opt,name=plain,proto3" json:"plain,omitempty"` - // Version of the KMS plugin API, now use “v1beta1” - Version string `protobuf:"bytes,2,opt,name=version" json:"version,omitempty"` + // Version of the KMS plugin API. + Version string `protobuf:"bytes,1,opt,name=version" json:"version,omitempty"` + // The data to be encrypted. + Plain []byte `protobuf:"bytes,2,opt,name=plain,proto3" json:"plain,omitempty"` } func (m *EncryptRequest) Reset() { *m = EncryptRequest{} } func (m *EncryptRequest) String() string { return proto.CompactTextString(m) } func (*EncryptRequest) ProtoMessage() {} -func (*EncryptRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } +func (*EncryptRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} } + +func (m *EncryptRequest) GetVersion() string { + if m != nil { + return m.Version + } + return "" +} + +func (m *EncryptRequest) GetPlain() []byte { + if m != nil { + return m.Plain + } + return nil +} type EncryptResponse struct { + // The encrypted data. Cipher []byte `protobuf:"bytes,1,opt,name=cipher,proto3" json:"cipher,omitempty"` } func (m *EncryptResponse) Reset() { *m = EncryptResponse{} } func (m *EncryptResponse) String() string { return proto.CompactTextString(m) } func (*EncryptResponse) ProtoMessage() {} -func (*EncryptResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } +func (*EncryptResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} } + +func (m *EncryptResponse) GetCipher() []byte { + if m != nil { + return m.Cipher + } + return nil +} func init() { + proto.RegisterType((*VersionRequest)(nil), "v1beta1.VersionRequest") + proto.RegisterType((*VersionResponse)(nil), "v1beta1.VersionResponse") proto.RegisterType((*DecryptRequest)(nil), "v1beta1.DecryptRequest") proto.RegisterType((*DecryptResponse)(nil), "v1beta1.DecryptResponse") proto.RegisterType((*EncryptRequest)(nil), "v1beta1.EncryptRequest") @@ -110,7 +211,11 @@ const _ = grpc.SupportPackageIsVersion4 // Client API for KMSService service type KMSServiceClient interface { + // Version returns the runtime name and runtime version. + Version(ctx context.Context, in *VersionRequest, opts ...grpc.CallOption) (*VersionResponse, error) + // Execute decryption operation in KMS provider. Decrypt(ctx context.Context, in *DecryptRequest, opts ...grpc.CallOption) (*DecryptResponse, error) + // Execute encryption operation in KMS provider. Encrypt(ctx context.Context, in *EncryptRequest, opts ...grpc.CallOption) (*EncryptResponse, error) } @@ -122,6 +227,15 @@ func NewKMSServiceClient(cc *grpc.ClientConn) KMSServiceClient { return &kMSServiceClient{cc} } +func (c *kMSServiceClient) Version(ctx context.Context, in *VersionRequest, opts ...grpc.CallOption) (*VersionResponse, error) { + out := new(VersionResponse) + err := grpc.Invoke(ctx, "/v1beta1.KMSService/Version", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *kMSServiceClient) Decrypt(ctx context.Context, in *DecryptRequest, opts ...grpc.CallOption) (*DecryptResponse, error) { out := new(DecryptResponse) err := grpc.Invoke(ctx, "/v1beta1.KMSService/Decrypt", in, out, c.cc, opts...) @@ -143,7 +257,11 @@ func (c *kMSServiceClient) Encrypt(ctx context.Context, in *EncryptRequest, opts // Server API for KMSService service type KMSServiceServer interface { + // Version returns the runtime name and runtime version. + Version(context.Context, *VersionRequest) (*VersionResponse, error) + // Execute decryption operation in KMS provider. Decrypt(context.Context, *DecryptRequest) (*DecryptResponse, error) + // Execute encryption operation in KMS provider. Encrypt(context.Context, *EncryptRequest) (*EncryptResponse, error) } @@ -151,6 +269,24 @@ func RegisterKMSServiceServer(s *grpc.Server, srv KMSServiceServer) { s.RegisterService(&_KMSService_serviceDesc, srv) } +func _KMSService_Version_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(VersionRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(KMSServiceServer).Version(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/v1beta1.KMSService/Version", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(KMSServiceServer).Version(ctx, req.(*VersionRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _KMSService_Decrypt_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(DecryptRequest) if err := dec(in); err != nil { @@ -191,6 +327,10 @@ var _KMSService_serviceDesc = grpc.ServiceDesc{ ServiceName: "v1beta1.KMSService", HandlerType: (*KMSServiceServer)(nil), Methods: []grpc.MethodDesc{ + { + MethodName: "Version", + Handler: _KMSService_Version_Handler, + }, { MethodName: "Decrypt", Handler: _KMSService_Decrypt_Handler, @@ -207,18 +347,23 @@ var _KMSService_serviceDesc = grpc.ServiceDesc{ func init() { proto.RegisterFile("service.proto", fileDescriptor0) } var fileDescriptor0 = []byte{ - // 207 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x2d, 0x4e, 0x2d, 0x2a, - 0xcb, 0x4c, 0x4e, 0xd5, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x2f, 0x33, 0x4c, 0x4a, 0x2d, - 0x49, 0x34, 0x54, 0x72, 0xe2, 0xe2, 0x73, 0x49, 0x4d, 0x2e, 0xaa, 0x2c, 0x28, 0x09, 0x4a, 0x2d, - 0x2c, 0x4d, 0x2d, 0x2e, 0x11, 0x12, 0xe3, 0x62, 0x4b, 0xce, 0x2c, 0xc8, 0x48, 0x2d, 0x92, 0x60, - 0x54, 0x60, 0xd4, 0xe0, 0x09, 0x82, 0xf2, 0x84, 0x24, 0xb8, 0xd8, 0xcb, 0x52, 0x8b, 0x8a, 0x33, - 0xf3, 0xf3, 0x24, 0x98, 0x14, 0x18, 0x35, 0x38, 0x83, 0x60, 0x5c, 0x25, 0x75, 0x2e, 0x7e, 0xb8, - 0x19, 0xc5, 0x05, 0xf9, 0x79, 0xc5, 0xa9, 0x42, 0x22, 0x5c, 0xac, 0x05, 0x39, 0x89, 0x99, 0x79, - 0x50, 0x33, 0x20, 0x1c, 0x25, 0x07, 0x2e, 0x3e, 0xd7, 0x3c, 0x14, 0xcb, 0xb0, 0xaa, 0xc3, 0x63, - 0x95, 0x26, 0x17, 0x3f, 0xdc, 0x04, 0xa8, 0x55, 0x38, 0xdc, 0x6b, 0xd4, 0xc3, 0xc8, 0xc5, 0xe5, - 0xed, 0x1b, 0x1c, 0x0c, 0xf1, 0xb7, 0x90, 0x1d, 0x17, 0x3b, 0xd4, 0x91, 0x42, 0xe2, 0x7a, 0x50, - 0xdf, 0xeb, 0xa1, 0x7a, 0x5d, 0x4a, 0x02, 0x53, 0x02, 0x62, 0x89, 0x12, 0x03, 0x48, 0x3f, 0xd4, - 0x66, 0x24, 0xfd, 0xa8, 0xbe, 0x41, 0xd2, 0x8f, 0xe6, 0x48, 0x25, 0x86, 0x24, 0x36, 0x70, 0xc0, - 0x1b, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff, 0xd2, 0x95, 0x8d, 0x5c, 0x89, 0x01, 0x00, 0x00, + // 279 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x52, 0xcd, 0x4a, 0xc4, 0x30, + 0x10, 0xde, 0xae, 0xb8, 0xc5, 0xb1, 0xb6, 0x10, 0x44, 0x8b, 0x27, 0xcd, 0x65, 0xd5, 0x43, 0x61, + 0xf5, 0x2e, 0x22, 0x7a, 0x12, 0x3d, 0x74, 0xc1, 0xab, 0x74, 0xcb, 0x80, 0x01, 0x9b, 0xc6, 0x24, + 0x5b, 0xf1, 0x1d, 0x7d, 0x28, 0xb1, 0x99, 0xd6, 0xb4, 0x22, 0xee, 0x71, 0x26, 0xdf, 0xdf, 0xcc, + 0x04, 0xf6, 0x0c, 0xea, 0x46, 0x94, 0x98, 0x29, 0x5d, 0xdb, 0x9a, 0x85, 0xcd, 0x62, 0x85, 0xb6, + 0x58, 0xf0, 0x73, 0x88, 0x9f, 0x50, 0x1b, 0x51, 0xcb, 0x1c, 0xdf, 0xd6, 0x68, 0x2c, 0x4b, 0x21, + 0x6c, 0x5c, 0x27, 0x0d, 0x8e, 0x83, 0xd3, 0x9d, 0xbc, 0x2b, 0xf9, 0x3b, 0x24, 0x3d, 0xd6, 0xa8, + 0x5a, 0x1a, 0xfc, 0x1b, 0xcc, 0x4e, 0x20, 0xd2, 0x6b, 0x69, 0x45, 0x85, 0xcf, 0xb2, 0xa8, 0x30, + 0x9d, 0xb6, 0xcf, 0xbb, 0xd4, 0x7b, 0x2c, 0x2a, 0x64, 0x73, 0x48, 0x3a, 0x48, 0x27, 0xb2, 0xd5, + 0xa2, 0x62, 0x6a, 0x93, 0x1b, 0xbf, 0x81, 0xf8, 0x16, 0x4b, 0xfd, 0xa1, 0xec, 0xbf, 0x21, 0xd9, + 0x01, 0xcc, 0x4a, 0xa1, 0x5e, 0x50, 0xb7, 0x8e, 0x51, 0x4e, 0x15, 0x9f, 0x43, 0xd2, 0x6b, 0x50, + 0xf8, 0x7d, 0xd8, 0x56, 0xaf, 0x85, 0x70, 0x12, 0x51, 0xee, 0x0a, 0x7e, 0x0d, 0xf1, 0x9d, 0xdc, + 0xd0, 0xac, 0x57, 0x98, 0xfa, 0x0a, 0x67, 0x90, 0xf4, 0x0a, 0x64, 0xf5, 0x93, 0x2a, 0xf0, 0x53, + 0x5d, 0x7c, 0x06, 0x00, 0xf7, 0x0f, 0xcb, 0xa5, 0x3b, 0x0e, 0xbb, 0x82, 0x90, 0x66, 0x66, 0x87, + 0x19, 0x9d, 0x28, 0x1b, 0xde, 0xe7, 0x28, 0xfd, 0xfd, 0xe0, 0x4c, 0xf8, 0xe4, 0x9b, 0x4f, 0x43, + 0x7a, 0xfc, 0xe1, 0xea, 0x3c, 0xfe, 0x68, 0x1f, 0x8e, 0x4f, 0xc9, 0x3d, 0xfe, 0x70, 0x1b, 0x1e, + 0x7f, 0x34, 0x24, 0x9f, 0xac, 0x66, 0xed, 0xef, 0xba, 0xfc, 0x0a, 0x00, 0x00, 0xff, 0xff, 0x28, + 0x69, 0xfc, 0xea, 0x6e, 0x02, 0x00, 0x00, } diff --git a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/v1beta1/service.proto b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/v1beta1/service.proto index 68b5bd0a091..489ff5f8308 100644 --- a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/v1beta1/service.proto +++ b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/v1beta1/service.proto @@ -2,28 +2,52 @@ syntax = "proto3"; package v1beta1; +// This service defines the public APIs for remote KMS provider. service KMSService { + // Version returns the runtime name and runtime version of the KMS provider. + rpc Version(VersionRequest) returns (VersionResponse) {} + + // Execute decryption operation in KMS provider. rpc Decrypt(DecryptRequest) returns (DecryptResponse) {} + // Execute encryption operation in KMS provider. rpc Encrypt(EncryptRequest) returns (EncryptResponse) {} } +message VersionRequest { + // Version of the KMS plugin API. + string version = 1; +} + +message VersionResponse { + // Version of the KMS plugin API. + string version = 1; + // Name of the KMS provider. + string runtime_name = 2; + // Version of the KMS provider. The string must be semver-compatible. + string runtime_version = 3; +} + message DecryptRequest { - bytes cipher = 1; - // Version of the KMS plugin API, now use “v1beta1” - string version = 2; + // Version of the KMS plugin API. + string version = 1; + // The data to be decrypted. + bytes cipher = 2; } message DecryptResponse { + // The decrypted data. bytes plain = 1; } message EncryptRequest { - bytes plain = 1; - // Version of the KMS plugin API, now use “v1beta1” - string version = 2; + // Version of the KMS plugin API. + string version = 1; + // The data to be encrypted. + bytes plain = 2; } message EncryptResponse { + // The encrypted data. bytes cipher = 1; } From 2e7af38d6b4c8ed9e1fb23930b98ed8d2ad68aa0 Mon Sep 17 00:00:00 2001 From: Wu Qiang Date: Thu, 25 Jan 2018 05:39:48 +0000 Subject: [PATCH 5/9] Update for review comments --- .../apiserver/pkg/server/options/encryptionconfig/types.go | 6 ++++-- .../pkg/storage/value/encrypt/envelope/grpc_service.go | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/types.go b/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/types.go index 02c604ce272..23b37debe25 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/types.go +++ b/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/types.go @@ -82,7 +82,9 @@ type KMSConfig struct { // +optional CacheSize int `json:"cachesize,omitempty"` // configfile is the path to the configuration file for the named KMS provider. - ConfigFile string `json:"configfile"` + // +optional + ConfigFile string `json:"configfile,omitempty"` // the gRPC server listening address, for example "unix:///var/run/kms-provider.sock". - Endpoint string `json:"endpoint"` + // +optional + Endpoint string `json:"endpoint,omitempty"` } diff --git a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/grpc_service.go b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/grpc_service.go index 8d68a23a3ce..cf33ab05d42 100644 --- a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/grpc_service.go +++ b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/grpc_service.go @@ -49,7 +49,7 @@ type gRPCService struct { // NewGRPCService returns an envelope.Service which use gRPC to communicate the remote KMS provider. func NewGRPCService(endpoint string) (Service, error) { - glog.Infof("Configure KMS provider with endpoint: %s", endpoint) + glog.V(4).Infof("Configure KMS provider with endpoint: %s", endpoint) protocol, addr, err := parseEndpoint(endpoint) if err != nil { @@ -106,7 +106,7 @@ func checkAPIVersion(kmsClient kmsapi.KMSServiceClient) error { response.Version, kmsapiVersion) } - glog.Infof("KMS provider %s initialized, version: %s", response.RuntimeName, response.RuntimeVersion) + glog.V(4).Infof("KMS provider %s initialized, version: %s", response.RuntimeName, response.RuntimeVersion) return nil } From 5ae61ed386e3fbc3b7e91d343afadadd52ac027d Mon Sep 17 00:00:00 2001 From: Wu Qiang Date: Fri, 26 Jan 2018 11:53:24 +0000 Subject: [PATCH 6/9] Remove configfile for kms in encryption config --- .../pkg/server/options/encryptionconfig/BUILD | 2 - .../server/options/encryptionconfig/config.go | 34 ++--- .../options/encryptionconfig/config_test.go | 61 ++++----- .../options/encryptionconfig/plugins.go | 118 ------------------ .../server/options/encryptionconfig/types.go | 6 +- .../value/encrypt/envelope/grpc_service.go | 43 ++++--- 6 files changed, 74 insertions(+), 190 deletions(-) delete mode 100644 staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/plugins.go diff --git a/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/BUILD b/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/BUILD index 94de9c826c0..aebe16461ab 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/BUILD +++ b/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/BUILD @@ -10,13 +10,11 @@ go_library( name = "go_default_library", srcs = [ "config.go", - "plugins.go", "types.go", ], importpath = "k8s.io/apiserver/pkg/server/options/encryptionconfig", deps = [ "//vendor/github.com/ghodss/yaml:go_default_library", - "//vendor/github.com/golang/glog:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", "//vendor/k8s.io/apiserver/pkg/storage/value:go_default_library", "//vendor/k8s.io/apiserver/pkg/storage/value/encrypt/aes:go_default_library", diff --git a/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/config.go b/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/config.go index 650b8a37c36..4c6fd5a39cf 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/config.go +++ b/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/config.go @@ -102,6 +102,9 @@ func ParseEncryptionConfiguration(f io.Reader) (map[schema.GroupResource]value.T return result, nil } +// The factory to create kms service. This is to make writing test easier. +var envelopeServiceFactory = envelope.NewGRPCService + // GetPrefixTransformers constructs and returns the appropriate prefix transformers for the passed resource using its configuration func GetPrefixTransformers(config *ResourceConfig) ([]value.PrefixTransformer, error) { var result []value.PrefixTransformer @@ -151,28 +154,15 @@ func GetPrefixTransformers(config *ResourceConfig) ([]value.PrefixTransformer, e return nil, fmt.Errorf("more than one provider specified in a single element, should split into different list elements") } - var envelopeService envelope.Service - if len(provider.KMS.ConfigFile) > 0 { - // There should be no KMS provider plugins on API server side in future. - f, err := os.Open(provider.KMS.ConfigFile) - if err != nil { - return nil, fmt.Errorf("error opening KMS provider configuration file %q: %v", provider.KMS.ConfigFile, err) - } - defer f.Close() - pluginFound := false - envelopeService, pluginFound, err = KMSPluginRegistry.getPlugin(provider.KMS.Name, f) - if err != nil { - return nil, fmt.Errorf("could not configure KMS plugin %q, %v", provider.KMS.Name, err) - } - if pluginFound == false { - return nil, fmt.Errorf("KMS plugin %q not found", provider.KMS.Name) - } - } else { - // Get gRPC client service with endpoint. - envelopeService, err = envelope.NewGRPCService(provider.KMS.Endpoint) - if err != nil { - return nil, fmt.Errorf("could not configure KMS plugin %q, error: %v", provider.KMS.Name, err) - } + // Ensure the endpoint is provided. + if len(provider.KMS.Endpoint) == 0 { + return nil, fmt.Errorf("remote KMS provider can't use empty string as endpoint") + } + + // Get gRPC client service with endpoint. + envelopeService, err := envelopeServiceFactory(provider.KMS.Endpoint) + if err != nil { + return nil, fmt.Errorf("could not configure KMS plugin %q, error: %v", provider.KMS.Name, err) } transformer, err = getEnvelopePrefixTransformer(provider.KMS, envelopeService, kmsTransformerPrefixV1) diff --git a/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/config_test.go b/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/config_test.go index ac0b3d75151..f85319bff58 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/config_test.go +++ b/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/config_test.go @@ -19,9 +19,6 @@ package encryptionconfig import ( "bytes" "encoding/base64" - "fmt" - "io" - "os" "strings" "testing" @@ -35,10 +32,6 @@ const ( sampleContextText = "0123456789" - // Modify these in all configurations if changed - testEnvelopeServiceConfigPath = "testproviderconfig" - testEnvelopeServiceProviderName = "testprovider" - correctConfigWithIdentityFirst = ` kind: EncryptionConfig apiVersion: v1 @@ -56,7 +49,7 @@ resources: secret: dGhpcyBpcyBwYXNzd29yZA== - kms: name: testprovider - configfile: testproviderconfig + endpoint: /tmp/testprovider.sock cachesize: 10 - aescbc: keys: @@ -89,7 +82,7 @@ resources: secret: YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY= - kms: name: testprovider - configfile: testproviderconfig + endpoint: /tmp/testprovider.sock cachesize: 10 - aescbc: keys: @@ -115,7 +108,7 @@ resources: secret: dGhpcyBpcyBwYXNzd29yZA== - kms: name: testprovider - configfile: testproviderconfig + endpoint: /tmp/testprovider.sock cachesize: 10 - identity: {} - secretbox: @@ -149,7 +142,7 @@ resources: secret: dGhpcyBpcyBwYXNzd29yZA== - kms: name: testprovider - configfile: testproviderconfig + endpoint: /tmp/testprovider.sock cachesize: 10 - identity: {} - aesgcm: @@ -169,7 +162,7 @@ resources: providers: - kms: name: testprovider - configfile: testproviderconfig + endpoint: /tmp/testprovider.sock cachesize: 10 - secretbox: keys: @@ -218,40 +211,45 @@ resources: - name: key2 secret: YSBzZWNyZXQgYSBzZWNyZXQ= ` + + incorrectConfigNoEndpointForKMS = ` +kind: EncryptionConfig +apiVersion: v1 +resources: + - resources: + - secrets + providers: + - kms: + name: testprovider + cachesize: 10 +` ) // testEnvelopeService is a mock envelope service which can be used to simulate remote Envelope services // for testing of the envelope transformer with other transformers. type testEnvelopeService struct { - disabled bool } func (t *testEnvelopeService) Decrypt(data []byte) ([]byte, error) { - if t.disabled { - return nil, fmt.Errorf("Envelope service was disabled") - } return base64.StdEncoding.DecodeString(string(data)) } func (t *testEnvelopeService) Encrypt(data []byte) ([]byte, error) { - if t.disabled { - return nil, fmt.Errorf("Envelope service was disabled") - } return []byte(base64.StdEncoding.EncodeToString(data)), nil } -func (t *testEnvelopeService) SetDisabledStatus(status bool) { - t.disabled = status +// The factory method to create mock envelope service. +func newMockEnvelopeService(endpoint string) (envelope.Service, error) { + return &testEnvelopeService{}, nil } -var _ envelope.Service = &testEnvelopeService{} - func TestEncryptionProviderConfigCorrect(t *testing.T) { - os.OpenFile(testEnvelopeServiceConfigPath, os.O_CREATE, 0666) - defer os.Remove(testEnvelopeServiceConfigPath) - KMSPluginRegistry.Register(testEnvelopeServiceProviderName, func(_ io.Reader) (envelope.Service, error) { - return &testEnvelopeService{}, nil - }) + // Set factory for mock envelope service + factory := envelopeServiceFactory + envelopeServiceFactory = newMockEnvelopeService + defer func() { + envelopeServiceFactory = factory + }() // Creates compound/prefix transformers with different ordering of available transformers. // Transforms data using one of them, and tries to untransform using the others. @@ -337,3 +335,10 @@ func TestEncryptionProviderConfigInvalidKey(t *testing.T) { t.Fatalf("invalid configuration file (bad AES key) got parsed:\n%s", incorrectConfigInvalidKey) } } + +// Throw error if kms has no endpoint +func TestEncryptionProviderConfigNoEndpointForKMS(t *testing.T) { + if _, err := ParseEncryptionConfiguration(strings.NewReader(incorrectConfigNoEndpointForKMS)); err == nil { + t.Fatalf("invalid configuration file (kms has no endpoint) got parsed:\n%s", incorrectConfigNoEndpointForKMS) + } +} diff --git a/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/plugins.go b/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/plugins.go deleted file mode 100644 index 310c7238f59..00000000000 --- a/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/plugins.go +++ /dev/null @@ -1,118 +0,0 @@ -/* -Copyright 2017 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 encryptionconfig - -import ( - "bytes" - "io" - "io/ioutil" - "reflect" - "sync" - - "github.com/golang/glog" - - "k8s.io/apiserver/pkg/storage/value/encrypt/envelope" -) - -// Factory is a function that returns an envelope Service for encryption providers. -// The config parameter provides an io.Reader handler to the factory in -// order to load specific configurations. If no configuration is provided -// the parameter is nil. -type Factory func(config io.Reader) (envelope.Service, error) - -// KMSPlugins contains all registered KMS options. -type KMSPlugins struct { - lock sync.RWMutex - registry map[string]Factory -} - -var ( - // PluginEnabledFn checks whether a plugin is enabled. By default, if you ask about it, it's enabled. - PluginEnabledFn = func(name string, config io.Reader) bool { - return true - } - - // KMSPluginRegistry contains the registered KMS plugins which can be used for configuring - // encryption providers. - KMSPluginRegistry = KMSPlugins{} -) - -// PluginEnabledFunc is a function type that can provide an external check on whether an admission plugin may be enabled -type PluginEnabledFunc func(name string, config io.Reader) bool - -// Register registers a plugin Factory by name. This -// is expected to happen during app startup. It does not allow -// registering a plugin by the same name twice. -func (ps *KMSPlugins) Register(name string, plugin Factory) { - ps.lock.Lock() - defer ps.lock.Unlock() - _, found := ps.registry[name] - if ps.registry == nil { - ps.registry = map[string]Factory{} - } - if found { - glog.Fatalf("KMS plugin %q was registered twice", name) - } else { - ps.registry[name] = plugin - glog.V(1).Infof("Registered KMS plugin %q", name) - } -} - -// getPlugin creates an instance of the named plugin. It returns `false` if the -// the name is not known. The error is returned only when the named provider was -// known but failed to initialize. The config parameter specifies the io.Reader -// handler of the configuration file for the cloud provider, or nil for no configuration. -func (ps *KMSPlugins) getPlugin(name string, config io.Reader) (envelope.Service, bool, error) { - f, found := ps.fetchPluginFromRegistry(name) - if !found { - return nil, false, nil - } - - config1, config2, err := splitStream(config) - if err != nil { - return nil, true, err - } - if !PluginEnabledFn(name, config1) { - return nil, true, nil - } - - ret, err := f(config2) - return ret, true, err -} - -// fetchPluginFromRegistry tries to get a registered plugin with the requested name. -func (ps *KMSPlugins) fetchPluginFromRegistry(name string) (Factory, bool) { - ps.lock.RLock() - defer ps.lock.RUnlock() - // Map lookup defaults to single value context - f, found := ps.registry[name] - return f, found -} - -// splitStream reads the stream bytes and constructs two copies of it. -func splitStream(config io.Reader) (io.Reader, io.Reader, error) { - if config == nil || reflect.ValueOf(config).IsNil() { - return nil, nil, nil - } - - configBytes, err := ioutil.ReadAll(config) - if err != nil { - return nil, nil, err - } - - return bytes.NewBuffer(configBytes), bytes.NewBuffer(configBytes), nil -} diff --git a/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/types.go b/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/types.go index 23b37debe25..67dfa6c9fce 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/types.go +++ b/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/types.go @@ -81,10 +81,6 @@ type KMSConfig struct { // cacheSize is the maximum number of secrets which are cached in memory. The default value is 1000. // +optional CacheSize int `json:"cachesize,omitempty"` - // configfile is the path to the configuration file for the named KMS provider. - // +optional - ConfigFile string `json:"configfile,omitempty"` // the gRPC server listening address, for example "unix:///var/run/kms-provider.sock". - // +optional - Endpoint string `json:"endpoint,omitempty"` + Endpoint string `json:"endpoint"` } diff --git a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/grpc_service.go b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/grpc_service.go index cf33ab05d42..67b0f62972f 100644 --- a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/grpc_service.go +++ b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/grpc_service.go @@ -38,6 +38,9 @@ const ( // Current version for the protocal interface definition. kmsapiVersion = "v1beta1" + + // The timeout that communicate with KMS server. + timeout = 30 * time.Second ) // The gRPC implementation for envelope.Service. @@ -51,16 +54,12 @@ type gRPCService struct { func NewGRPCService(endpoint string) (Service, error) { glog.V(4).Infof("Configure KMS provider with endpoint: %s", endpoint) - protocol, addr, err := parseEndpoint(endpoint) + addr, err := parseEndpoint(endpoint) if err != nil { return nil, err } - dialer := func(addr string, timeout time.Duration) (net.Conn, error) { - return net.DialTimeout(protocol, addr, timeout) - } - - connection, err := grpc.Dial(addr, grpc.WithInsecure(), grpc.WithDialer(dialer)) + connection, err := grpc.Dial(addr, grpc.WithInsecure(), grpc.WithTimeout(timeout), grpc.WithDialer(unixDial)) if err != nil { return nil, fmt.Errorf("connect remote KMS provider %q failed, error: %v", addr, err) } @@ -76,28 +75,36 @@ func NewGRPCService(endpoint string) (Service, error) { return &gRPCService{kmsClient: kmsClient, connection: connection}, nil } +// This dialer explicitly ask gRPC to use unix socket as network. +func unixDial(addr string, timeout time.Duration) (net.Conn, error) { + return net.DialTimeout(unixProtocol, addr, timeout) +} + // Parse the endpoint to extract schema, host or path. -func parseEndpoint(endpoint string) (string, string, error) { +func parseEndpoint(endpoint string) (string, error) { if len(endpoint) == 0 { - return "", "", fmt.Errorf("remote KMS provider can't use empty string as endpoint") + return "", fmt.Errorf("remote KMS provider can't use empty string as endpoint") } u, err := url.Parse(endpoint) if err != nil { - return "", "", fmt.Errorf("invalid endpoint %q for remote KMS provider, error: %v", endpoint, err) + return "", fmt.Errorf("invalid endpoint %q for remote KMS provider, error: %v", endpoint, err) } if u.Scheme != unixProtocol { - return "", "", fmt.Errorf("unsupported scheme %q for remote KMS provider", u.Scheme) + return "", fmt.Errorf("unsupported scheme %q for remote KMS provider", u.Scheme) } - return unixProtocol, u.Path, nil + return u.Path, nil } // Check the KMS provider API version. -// Only matching kubeRuntimeAPIVersion is supported now. +// Only matching kmsapiVersion is supported now. func checkAPIVersion(kmsClient kmsapi.KMSServiceClient) error { + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + request := &kmsapi.VersionRequest{Version: kmsapiVersion} - response, err := kmsClient.Version(context.Background(), request) + response, err := kmsClient.Version(ctx, request) if err != nil { return fmt.Errorf("failed get version from remote KMS provider: %v", err) } @@ -112,8 +119,11 @@ func checkAPIVersion(kmsClient kmsapi.KMSServiceClient) error { // Decrypt a given data string to obtain the original byte data. func (g *gRPCService) Decrypt(cipher []byte) ([]byte, error) { + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + request := &kmsapi.DecryptRequest{Cipher: cipher, Version: kmsapiVersion} - response, err := g.kmsClient.Decrypt(context.Background(), request) + response, err := g.kmsClient.Decrypt(ctx, request) if err != nil { return nil, err } @@ -122,8 +132,11 @@ func (g *gRPCService) Decrypt(cipher []byte) ([]byte, error) { // Encrypt bytes to a string ciphertext. func (g *gRPCService) Encrypt(plain []byte) ([]byte, error) { + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + request := &kmsapi.EncryptRequest{Plain: plain, Version: kmsapiVersion} - response, err := g.kmsClient.Encrypt(context.Background(), request) + response, err := g.kmsClient.Encrypt(ctx, request) if err != nil { return nil, err } From 9825018e4a004523492893433604439b1f2acd22 Mon Sep 17 00:00:00 2001 From: Wu Qiang Date: Mon, 29 Jan 2018 06:00:57 +0000 Subject: [PATCH 7/9] Add generated script for kms api pb file --- hack/.golint_failures | 1 + hack/update-generated-kms-dockerized.sh | 62 +++++++++++++++++++ hack/update-generated-kms.sh | 29 +++++++++ .../value/encrypt/envelope/v1beta1/BUILD | 2 +- .../encrypt/envelope/v1beta1/service.pb.go | 41 ++++++------ .../encrypt/envelope/v1beta1/service.proto | 1 + 6 files changed, 115 insertions(+), 21 deletions(-) create mode 100755 hack/update-generated-kms-dockerized.sh create mode 100755 hack/update-generated-kms.sh diff --git a/hack/.golint_failures b/hack/.golint_failures index 19c8badcf11..4f14f014fac 100644 --- a/hack/.golint_failures +++ b/hack/.golint_failures @@ -605,6 +605,7 @@ staging/src/k8s.io/apiserver/pkg/storage/storagebackend staging/src/k8s.io/apiserver/pkg/storage/testing staging/src/k8s.io/apiserver/pkg/storage/tests staging/src/k8s.io/apiserver/pkg/storage/value +staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/v1beta1 staging/src/k8s.io/apiserver/pkg/util/feature staging/src/k8s.io/apiserver/pkg/util/flag staging/src/k8s.io/apiserver/pkg/util/proxy diff --git a/hack/update-generated-kms-dockerized.sh b/hack/update-generated-kms-dockerized.sh new file mode 100755 index 00000000000..82db74f6d5f --- /dev/null +++ b/hack/update-generated-kms-dockerized.sh @@ -0,0 +1,62 @@ +#!/bin/bash + +# Copyright 2018 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. + +set -o errexit +set -o nounset +set -o pipefail + +KUBE_ROOT=$(dirname "${BASH_SOURCE}")/.. +KUBE_REMOTE_RUNTIME_ROOT="${KUBE_ROOT}/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/v1beta1/" +source "${KUBE_ROOT}/hack/lib/init.sh" + +kube::golang::setup_env + +BINS=( + vendor/k8s.io/code-generator/cmd/go-to-protobuf/protoc-gen-gogo +) +make -C "${KUBE_ROOT}" WHAT="${BINS[*]}" + +if [[ -z "$(which protoc)" || "$(protoc --version)" != "libprotoc 3."* ]]; then + echo "Generating protobuf requires protoc 3.0.0-beta1 or newer. Please download and" + echo "install the platform appropriate Protobuf package for your OS: " + echo + echo " https://github.com/google/protobuf/releases" + echo + echo "WARNING: Protobuf changes are not being validated" + exit 1 +fi + +function cleanup { + rm -f ${KUBE_REMOTE_RUNTIME_ROOT}/service.pb.go.bak +} + +trap cleanup EXIT + +gogopath=$(dirname $(kube::util::find-binary "protoc-gen-gogo")) + +PATH="${gogopath}:${PATH}" \ + protoc \ + --proto_path="${KUBE_REMOTE_RUNTIME_ROOT}" \ + --proto_path="${KUBE_ROOT}/vendor" \ + --gogo_out=plugins=grpc:${KUBE_REMOTE_RUNTIME_ROOT} ${KUBE_REMOTE_RUNTIME_ROOT}/service.proto + +# Update boilerplate for the generated file. +echo "$(cat hack/boilerplate/boilerplate.go.txt ${KUBE_REMOTE_RUNTIME_ROOT}/service.pb.go)" > ${KUBE_REMOTE_RUNTIME_ROOT}/service.pb.go +sed -i".bak" "s/Copyright YEAR/Copyright $(date '+%Y')/g" ${KUBE_REMOTE_RUNTIME_ROOT}/service.pb.go + +# Run gofmt to clean up the generated code. +kube::golang::verify_go_version +gofmt -l -s -w ${KUBE_REMOTE_RUNTIME_ROOT}/service.pb.go diff --git a/hack/update-generated-kms.sh b/hack/update-generated-kms.sh new file mode 100755 index 00000000000..95a0ee80ca3 --- /dev/null +++ b/hack/update-generated-kms.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +# Copyright 2018 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. + +set -o errexit +set -o nounset +set -o pipefail + +KUBE_ROOT=$(dirname "${BASH_SOURCE}")/.. + +# NOTE: All output from this script needs to be copied back to the calling +# source tree. This is managed in kube::build::copy_output in build/common.sh. +# If the output set is changed update that function. + +${KUBE_ROOT}/build/run.sh hack/update-generated-kms-dockerized.sh "$@" + +# ex: ts=2 sw=2 et filetype=sh diff --git a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/v1beta1/BUILD b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/v1beta1/BUILD index d45a85b373f..5fafc66b161 100644 --- a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/v1beta1/BUILD +++ b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/v1beta1/BUILD @@ -12,7 +12,7 @@ go_library( importpath = "k8s.io/apiserver/pkg/storage/value/encrypt/envelope/v1beta1", visibility = ["//visibility:public"], deps = [ - "//vendor/github.com/golang/protobuf/proto:go_default_library", + "//vendor/github.com/gogo/protobuf/proto:go_default_library", "//vendor/golang.org/x/net/context:go_default_library", "//vendor/google.golang.org/grpc:go_default_library", ], diff --git a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/v1beta1/service.pb.go b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/v1beta1/service.pb.go index 118d2e72faa..9e61bef00ac 100644 --- a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/v1beta1/service.pb.go +++ b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/v1beta1/service.pb.go @@ -1,5 +1,5 @@ /* -Copyright 2017 The Kubernetes Authors. +Copyright 2018 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. @@ -14,8 +14,9 @@ See the License for the specific language governing permissions and limitations under the License. */ -// Code generated by protoc-gen-go. DO NOT EDIT. +// Code generated by protoc-gen-gogo. // source: service.proto +// DO NOT EDIT! /* Package v1beta1 is a generated protocol buffer package. @@ -33,7 +34,7 @@ It has these top-level messages: */ package v1beta1 -import proto "github.com/golang/protobuf/proto" +import proto "github.com/gogo/protobuf/proto" import fmt "fmt" import math "math" @@ -51,17 +52,17 @@ var _ = math.Inf // is compatible with the proto package it is being compiled against. // A compilation error at this line likely means your copy of the // proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package +const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package type VersionRequest struct { // Version of the KMS plugin API. - Version string `protobuf:"bytes,1,opt,name=version" json:"version,omitempty"` + Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"` } func (m *VersionRequest) Reset() { *m = VersionRequest{} } func (m *VersionRequest) String() string { return proto.CompactTextString(m) } func (*VersionRequest) ProtoMessage() {} -func (*VersionRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } +func (*VersionRequest) Descriptor() ([]byte, []int) { return fileDescriptorService, []int{0} } func (m *VersionRequest) GetVersion() string { if m != nil { @@ -72,17 +73,17 @@ func (m *VersionRequest) GetVersion() string { type VersionResponse struct { // Version of the KMS plugin API. - Version string `protobuf:"bytes,1,opt,name=version" json:"version,omitempty"` + Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"` // Name of the KMS provider. - RuntimeName string `protobuf:"bytes,2,opt,name=runtime_name,json=runtimeName" json:"runtime_name,omitempty"` + RuntimeName string `protobuf:"bytes,2,opt,name=runtime_name,json=runtimeName,proto3" json:"runtime_name,omitempty"` // Version of the KMS provider. The string must be semver-compatible. - RuntimeVersion string `protobuf:"bytes,3,opt,name=runtime_version,json=runtimeVersion" json:"runtime_version,omitempty"` + RuntimeVersion string `protobuf:"bytes,3,opt,name=runtime_version,json=runtimeVersion,proto3" json:"runtime_version,omitempty"` } func (m *VersionResponse) Reset() { *m = VersionResponse{} } func (m *VersionResponse) String() string { return proto.CompactTextString(m) } func (*VersionResponse) ProtoMessage() {} -func (*VersionResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } +func (*VersionResponse) Descriptor() ([]byte, []int) { return fileDescriptorService, []int{1} } func (m *VersionResponse) GetVersion() string { if m != nil { @@ -107,7 +108,7 @@ func (m *VersionResponse) GetRuntimeVersion() string { type DecryptRequest struct { // Version of the KMS plugin API. - Version string `protobuf:"bytes,1,opt,name=version" json:"version,omitempty"` + Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"` // The data to be decrypted. Cipher []byte `protobuf:"bytes,2,opt,name=cipher,proto3" json:"cipher,omitempty"` } @@ -115,7 +116,7 @@ type DecryptRequest struct { func (m *DecryptRequest) Reset() { *m = DecryptRequest{} } func (m *DecryptRequest) String() string { return proto.CompactTextString(m) } func (*DecryptRequest) ProtoMessage() {} -func (*DecryptRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } +func (*DecryptRequest) Descriptor() ([]byte, []int) { return fileDescriptorService, []int{2} } func (m *DecryptRequest) GetVersion() string { if m != nil { @@ -139,7 +140,7 @@ type DecryptResponse struct { func (m *DecryptResponse) Reset() { *m = DecryptResponse{} } func (m *DecryptResponse) String() string { return proto.CompactTextString(m) } func (*DecryptResponse) ProtoMessage() {} -func (*DecryptResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } +func (*DecryptResponse) Descriptor() ([]byte, []int) { return fileDescriptorService, []int{3} } func (m *DecryptResponse) GetPlain() []byte { if m != nil { @@ -150,7 +151,7 @@ func (m *DecryptResponse) GetPlain() []byte { type EncryptRequest struct { // Version of the KMS plugin API. - Version string `protobuf:"bytes,1,opt,name=version" json:"version,omitempty"` + Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"` // The data to be encrypted. Plain []byte `protobuf:"bytes,2,opt,name=plain,proto3" json:"plain,omitempty"` } @@ -158,7 +159,7 @@ type EncryptRequest struct { func (m *EncryptRequest) Reset() { *m = EncryptRequest{} } func (m *EncryptRequest) String() string { return proto.CompactTextString(m) } func (*EncryptRequest) ProtoMessage() {} -func (*EncryptRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} } +func (*EncryptRequest) Descriptor() ([]byte, []int) { return fileDescriptorService, []int{4} } func (m *EncryptRequest) GetVersion() string { if m != nil { @@ -182,7 +183,7 @@ type EncryptResponse struct { func (m *EncryptResponse) Reset() { *m = EncryptResponse{} } func (m *EncryptResponse) String() string { return proto.CompactTextString(m) } func (*EncryptResponse) ProtoMessage() {} -func (*EncryptResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} } +func (*EncryptResponse) Descriptor() ([]byte, []int) { return fileDescriptorService, []int{5} } func (m *EncryptResponse) GetCipher() []byte { if m != nil { @@ -211,7 +212,7 @@ const _ = grpc.SupportPackageIsVersion4 // Client API for KMSService service type KMSServiceClient interface { - // Version returns the runtime name and runtime version. + // Version returns the runtime name and runtime version of the KMS provider. Version(ctx context.Context, in *VersionRequest, opts ...grpc.CallOption) (*VersionResponse, error) // Execute decryption operation in KMS provider. Decrypt(ctx context.Context, in *DecryptRequest, opts ...grpc.CallOption) (*DecryptResponse, error) @@ -257,7 +258,7 @@ func (c *kMSServiceClient) Encrypt(ctx context.Context, in *EncryptRequest, opts // Server API for KMSService service type KMSServiceServer interface { - // Version returns the runtime name and runtime version. + // Version returns the runtime name and runtime version of the KMS provider. Version(context.Context, *VersionRequest) (*VersionResponse, error) // Execute decryption operation in KMS provider. Decrypt(context.Context, *DecryptRequest) (*DecryptResponse, error) @@ -344,9 +345,9 @@ var _KMSService_serviceDesc = grpc.ServiceDesc{ Metadata: "service.proto", } -func init() { proto.RegisterFile("service.proto", fileDescriptor0) } +func init() { proto.RegisterFile("service.proto", fileDescriptorService) } -var fileDescriptor0 = []byte{ +var fileDescriptorService = []byte{ // 279 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x52, 0xcd, 0x4a, 0xc4, 0x30, 0x10, 0xde, 0xae, 0xb8, 0xc5, 0xb1, 0xb6, 0x10, 0x44, 0x8b, 0x27, 0xcd, 0x65, 0xd5, 0x43, 0x61, diff --git a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/v1beta1/service.proto b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/v1beta1/service.proto index 489ff5f8308..90e62acaefd 100644 --- a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/v1beta1/service.proto +++ b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/v1beta1/service.proto @@ -1,3 +1,4 @@ +// To regenerate service.pb.go run hack/update-generated-kms.sh syntax = "proto3"; package v1beta1; From c28f66c7e7f5170338a7348d5f72201db4be8f26 Mon Sep 17 00:00:00 2001 From: Wu Qiang Date: Thu, 8 Feb 2018 01:29:56 +0000 Subject: [PATCH 8/9] Add verify script for kms generated file --- hack/update-generated-kms-dockerized.sh | 14 ++++---- hack/verify-generated-kms.sh | 45 +++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 7 deletions(-) create mode 100755 hack/verify-generated-kms.sh diff --git a/hack/update-generated-kms-dockerized.sh b/hack/update-generated-kms-dockerized.sh index 82db74f6d5f..d28ab214faa 100755 --- a/hack/update-generated-kms-dockerized.sh +++ b/hack/update-generated-kms-dockerized.sh @@ -19,7 +19,7 @@ set -o nounset set -o pipefail KUBE_ROOT=$(dirname "${BASH_SOURCE}")/.. -KUBE_REMOTE_RUNTIME_ROOT="${KUBE_ROOT}/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/v1beta1/" +KUBE_KMS_GRPC_ROOT="${KUBE_ROOT}/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/v1beta1/" source "${KUBE_ROOT}/hack/lib/init.sh" kube::golang::setup_env @@ -40,7 +40,7 @@ if [[ -z "$(which protoc)" || "$(protoc --version)" != "libprotoc 3."* ]]; then fi function cleanup { - rm -f ${KUBE_REMOTE_RUNTIME_ROOT}/service.pb.go.bak + rm -f ${KUBE_KMS_GRPC_ROOT}/service.pb.go.bak } trap cleanup EXIT @@ -49,14 +49,14 @@ gogopath=$(dirname $(kube::util::find-binary "protoc-gen-gogo")) PATH="${gogopath}:${PATH}" \ protoc \ - --proto_path="${KUBE_REMOTE_RUNTIME_ROOT}" \ + --proto_path="${KUBE_KMS_GRPC_ROOT}" \ --proto_path="${KUBE_ROOT}/vendor" \ - --gogo_out=plugins=grpc:${KUBE_REMOTE_RUNTIME_ROOT} ${KUBE_REMOTE_RUNTIME_ROOT}/service.proto + --gogo_out=plugins=grpc:${KUBE_KMS_GRPC_ROOT} ${KUBE_KMS_GRPC_ROOT}/service.proto # Update boilerplate for the generated file. -echo "$(cat hack/boilerplate/boilerplate.go.txt ${KUBE_REMOTE_RUNTIME_ROOT}/service.pb.go)" > ${KUBE_REMOTE_RUNTIME_ROOT}/service.pb.go -sed -i".bak" "s/Copyright YEAR/Copyright $(date '+%Y')/g" ${KUBE_REMOTE_RUNTIME_ROOT}/service.pb.go +echo "$(cat hack/boilerplate/boilerplate.go.txt ${KUBE_KMS_GRPC_ROOT}/service.pb.go)" > ${KUBE_KMS_GRPC_ROOT}/service.pb.go +sed -i".bak" "s/Copyright YEAR/Copyright $(date '+%Y')/g" ${KUBE_KMS_GRPC_ROOT}/service.pb.go # Run gofmt to clean up the generated code. kube::golang::verify_go_version -gofmt -l -s -w ${KUBE_REMOTE_RUNTIME_ROOT}/service.pb.go +gofmt -l -s -w ${KUBE_KMS_GRPC_ROOT}/service.pb.go diff --git a/hack/verify-generated-kms.sh b/hack/verify-generated-kms.sh new file mode 100755 index 00000000000..03738b52e04 --- /dev/null +++ b/hack/verify-generated-kms.sh @@ -0,0 +1,45 @@ +#!/bin/bash + +# Copyright 2018 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. + +set -o errexit +set -o nounset +set -o pipefail + +KUBE_ROOT=$(dirname "${BASH_SOURCE}")/.. +KUBE_KMS_GRPC_ROOT="${KUBE_ROOT}/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/v1beta1/" +source "${KUBE_ROOT}/hack/lib/init.sh" + +kube::golang::setup_env + +function cleanup { + rm -rf ${KUBE_KMS_GRPC_ROOT}/_tmp/ +} + +trap cleanup EXIT + +mkdir -p ${KUBE_KMS_GRPC_ROOT}/_tmp +cp ${KUBE_KMS_GRPC_ROOT}/service.pb.go ${KUBE_KMS_GRPC_ROOT}/_tmp/ + +ret=0 +KUBE_VERBOSE=3 "${KUBE_ROOT}/hack/update-generated-kms.sh" +diff -I "gzipped FileDescriptorProto" -I "0x" -Naupr ${KUBE_KMS_GRPC_ROOT}/_tmp/service.pb.go ${KUBE_KMS_GRPC_ROOT}/service.pb.go || ret=$? +if [[ $ret -eq 0 ]]; then + echo "Generated KMS gRPC is up to date." + cp ${KUBE_KMS_GRPC_ROOT}/_tmp/service.pb.go ${KUBE_KMS_GRPC_ROOT}/ +else + echo "Generated KMS gRPC is out of date. Please run hack/update-generated-kms.sh" + exit 1 +fi From 31f74303fc48df5d88105c9742a103eae742f478 Mon Sep 17 00:00:00 2001 From: Wu Qiang Date: Fri, 9 Feb 2018 01:23:25 +0000 Subject: [PATCH 9/9] Update endpoint value in test code --- .../pkg/server/options/encryptionconfig/config_test.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/config_test.go b/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/config_test.go index f85319bff58..957d7dedeb9 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/config_test.go +++ b/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/config_test.go @@ -49,7 +49,7 @@ resources: secret: dGhpcyBpcyBwYXNzd29yZA== - kms: name: testprovider - endpoint: /tmp/testprovider.sock + endpoint: unix:///tmp/testprovider.sock cachesize: 10 - aescbc: keys: @@ -82,7 +82,7 @@ resources: secret: YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY= - kms: name: testprovider - endpoint: /tmp/testprovider.sock + endpoint: unix:///tmp/testprovider.sock cachesize: 10 - aescbc: keys: @@ -108,7 +108,7 @@ resources: secret: dGhpcyBpcyBwYXNzd29yZA== - kms: name: testprovider - endpoint: /tmp/testprovider.sock + endpoint: unix:///tmp/testprovider.sock cachesize: 10 - identity: {} - secretbox: @@ -142,7 +142,7 @@ resources: secret: dGhpcyBpcyBwYXNzd29yZA== - kms: name: testprovider - endpoint: /tmp/testprovider.sock + endpoint: unix:///tmp/testprovider.sock cachesize: 10 - identity: {} - aesgcm: @@ -162,7 +162,7 @@ resources: providers: - kms: name: testprovider - endpoint: /tmp/testprovider.sock + endpoint: unix:///tmp/testprovider.sock cachesize: 10 - secretbox: keys: