diff --git a/contracts b/contracts index ae6424762..795f11fa1 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit ae64247620dfa3229491243b5466b0584425705a +Subproject commit 795f11fa13aa853eff9e09e2b0c97a255acc9180 diff --git a/pkg/adapters/grpc/secret_grpc.go b/pkg/adapters/grpc/secret_grpc.go new file mode 100644 index 000000000..36e5eb60b --- /dev/null +++ b/pkg/adapters/grpc/secret_grpc.go @@ -0,0 +1,90 @@ +// Copyright 2021 Nitric Pty Ltd. +// +// 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 grpc + +import ( + "context" + + pb "github.com/nitric-dev/membrane/interfaces/nitric/v1" + "github.com/nitric-dev/membrane/pkg/plugins/secret" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +// GRPC Interface for registered Nitric Secret Plugins +type SecretServer struct { + pb.UnimplementedSecretServiceServer + secretPlugin secret.SecretService +} + +func (s *SecretServer) checkPluginRegistered() error { + if s.secretPlugin == nil { + return status.Errorf(codes.Unimplemented, "Secret plugin not registered") + } + + return nil +} + +func (s *SecretServer) Put(ctx context.Context, req *pb.SecretPutRequest) (*pb.SecretPutResponse, error) { + if err := s.checkPluginRegistered(); err == nil { + if r, err := s.secretPlugin.Put(&secret.Secret{ + Name: req.GetSecret().GetName(), + }, req.GetValue()); err == nil { + return &pb.SecretPutResponse{ + SecretVersion: &pb.SecretVersion{ + Secret: &pb.Secret{ + Name: r.SecretVersion.Secret.Name, + }, + Version: r.SecretVersion.Version, + }, + }, nil + } else { + return nil, NewGrpcError("SecretService.Put", err) + } + } else { + return nil, err + } +} + +func (s *SecretServer) Access(ctx context.Context, req *pb.SecretAccessRequest) (*pb.SecretAccessResponse, error) { + if err := s.checkPluginRegistered(); err == nil { + if s, err := s.secretPlugin.Access(&secret.SecretVersion{ + Secret: &secret.Secret{ + Name: req.GetSecretVersion().GetSecret().GetName(), + }, + Version: req.GetSecretVersion().GetVersion(), + }); err == nil { + return &pb.SecretAccessResponse{ + SecretVersion: &pb.SecretVersion{ + Secret: &pb.Secret{ + Name: s.SecretVersion.Secret.Name, + }, + Version: s.SecretVersion.Version, + }, + Value: s.Value, + }, nil + } else { + return nil, NewGrpcError("SecretService.Access", err) + } + } else { + return nil, err + } +} + +func NewSecretServer(secretPlugin secret.SecretService) pb.SecretServiceServer { + return &SecretServer{ + secretPlugin: secretPlugin, + } +} diff --git a/pkg/membrane/membrane.go b/pkg/membrane/membrane.go index 391e380fa..5f758a00a 100644 --- a/pkg/membrane/membrane.go +++ b/pkg/membrane/membrane.go @@ -23,6 +23,7 @@ import ( "strings" grpc2 "github.com/nitric-dev/membrane/pkg/adapters/grpc" + "github.com/nitric-dev/membrane/pkg/plugins/secret" "github.com/nitric-dev/membrane/pkg/utils" "github.com/nitric-dev/membrane/pkg/worker" @@ -49,6 +50,7 @@ type MembraneOptions struct { StoragePlugin storage.StorageService QueuePlugin queue.QueueService GatewayPlugin gateway.GatewayService + SecretPlugin secret.SecretService SuppressLogs bool TolerateMissingServices bool @@ -83,6 +85,7 @@ type Membrane struct { storagePlugin storage.StorageService gatewayPlugin gateway.GatewayService queuePlugin queue.QueueService + secretPlugin secret.SecretService // Tolerate if provider specific plugins aren't available for some services. // Not this does not include the gateway service @@ -106,6 +109,10 @@ func (s *Membrane) log(log string) { } } +func (s *Membrane) CreateSecretServer() v1.SecretServiceServer { + return grpc2.NewSecretServer(s.secretPlugin) +} + // Create a new Nitric Document Server func (s *Membrane) createDocumentServer() v1.DocumentServiceServer { return grpc2.NewDocumentServer(s.documentPlugin) @@ -155,6 +162,9 @@ func (s *Membrane) Start() error { var opts []grpc.ServerOption s.grpcServer = grpc.NewServer(opts...) + secretServer := s.CreateSecretServer() + v1.RegisterSecretServiceServer(s.grpcServer, secretServer) + // Load & Register the GRPC service plugins documentServer := s.createDocumentServer() v1.RegisterDocumentServiceServer(s.grpcServer, documentServer) @@ -352,6 +362,7 @@ func New(options *MembraneOptions) (*Membrane, error) { storagePlugin: options.StoragePlugin, queuePlugin: options.QueuePlugin, gatewayPlugin: options.GatewayPlugin, + secretPlugin: options.SecretPlugin, suppressLogs: options.SuppressLogs, tolerateMissingServices: options.TolerateMissingServices, mode: *options.Mode, diff --git a/pkg/plugins/secret/secret.go b/pkg/plugins/secret/secret.go new file mode 100644 index 000000000..ec78970b8 --- /dev/null +++ b/pkg/plugins/secret/secret.go @@ -0,0 +1,38 @@ +// Copyright 2021 Nitric Pty Ltd. +// +// 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 secret + +import "fmt" + +type SecretService interface { + // Put - Creates a new version for a given secret + Put(*Secret, []byte) (*SecretPutResponse, error) + // Access - Retrieves the value for a given secret version + Access(*SecretVersion) (*SecretAccessResponse, error) +} + +type UnimplementedSecretPlugin struct { + SecretService +} + +var _ SecretService = (*UnimplementedSecretPlugin)(nil) + +func (*UnimplementedSecretPlugin) Put(secret *Secret, value []byte) (*SecretPutResponse, error) { + return nil, fmt.Errorf("UNIMPLEMENTED") +} + +func (*UnimplementedSecretPlugin) Access(version *SecretVersion) (*SecretAccessResponse, error) { + return nil, fmt.Errorf("UNIMPLEMENTED") +} diff --git a/pkg/plugins/secret/types.go b/pkg/plugins/secret/types.go new file mode 100644 index 000000000..ac3f86c13 --- /dev/null +++ b/pkg/plugins/secret/types.go @@ -0,0 +1,40 @@ +// Copyright 2021 Nitric Pty Ltd. +// +// 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 secret + +// Secret - Represents a container for secret versions +type Secret struct { + Name string +} + +// SecretVersion - A version of a secret +type SecretVersion struct { + Secret *Secret + + // Version - the specific secret version this represents + // Specifying "latest" will always retrieve the latest version of the secret + Version string +} + +// SecretAccessResponse - Return value for a secret access request +type SecretAccessResponse struct { + SecretVersion *SecretVersion + Value []byte +} + +// SecretPutResponse - Return value for a secret put request +type SecretPutResponse struct { + SecretVersion *SecretVersion +}