2023-03-15 16:00:52 +00:00
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
2018-01-18 21:49:20 +00:00
package plugin
import (
"context"
"encoding/json"
"errors"
"fmt"
2018-11-07 01:21:24 +00:00
"time"
2018-01-18 21:49:20 +00:00
2019-04-12 21:54:35 +00:00
"github.com/hashicorp/vault/sdk/helper/consts"
"github.com/hashicorp/vault/sdk/helper/license"
"github.com/hashicorp/vault/sdk/helper/pluginutil"
"github.com/hashicorp/vault/sdk/helper/wrapping"
"github.com/hashicorp/vault/sdk/logical"
"github.com/hashicorp/vault/sdk/plugin/pb"
2018-11-07 01:21:24 +00:00
"google.golang.org/grpc"
2020-05-27 18:28:00 +00:00
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
2018-01-18 21:49:20 +00:00
)
2022-12-02 18:12:05 +00:00
var errMissingSystemView = errors . New ( "missing system view implementation: this method should not be called during plugin Setup, but only during and after Initialize" )
2018-01-18 21:49:20 +00:00
func newGRPCSystemView ( conn * grpc . ClientConn ) * gRPCSystemViewClient {
return & gRPCSystemViewClient {
client : pb . NewSystemViewClient ( conn ) ,
}
}
2022-12-07 18:29:51 +00:00
var _ logical . SystemView = & gRPCSystemViewClient { }
2018-01-18 21:49:20 +00:00
type gRPCSystemViewClient struct {
client pb . SystemViewClient
}
func ( s * gRPCSystemViewClient ) DefaultLeaseTTL ( ) time . Duration {
reply , err := s . client . DefaultLeaseTTL ( context . Background ( ) , & pb . Empty { } )
if err != nil {
return 0
}
return time . Duration ( reply . TTL )
}
func ( s * gRPCSystemViewClient ) MaxLeaseTTL ( ) time . Duration {
reply , err := s . client . MaxLeaseTTL ( context . Background ( ) , & pb . Empty { } )
if err != nil {
return 0
}
return time . Duration ( reply . TTL )
}
func ( s * gRPCSystemViewClient ) Tainted ( ) bool {
reply , err := s . client . Tainted ( context . Background ( ) , & pb . Empty { } )
if err != nil {
return false
}
return reply . Tainted
}
func ( s * gRPCSystemViewClient ) CachingDisabled ( ) bool {
reply , err := s . client . CachingDisabled ( context . Background ( ) , & pb . Empty { } )
if err != nil {
return false
}
return reply . Disabled
}
func ( s * gRPCSystemViewClient ) ReplicationState ( ) consts . ReplicationState {
reply , err := s . client . ReplicationState ( context . Background ( ) , & pb . Empty { } )
if err != nil {
2018-01-23 02:44:38 +00:00
return consts . ReplicationUnknown
2018-01-18 21:49:20 +00:00
}
return consts . ReplicationState ( reply . State )
}
2018-01-19 06:44:44 +00:00
func ( s * gRPCSystemViewClient ) ResponseWrapData ( ctx context . Context , data map [ string ] interface { } , ttl time . Duration , jwt bool ) ( * wrapping . ResponseWrapInfo , error ) {
2018-01-18 21:49:20 +00:00
buf , err := json . Marshal ( data )
if err != nil {
return nil , err
}
2018-01-19 06:44:44 +00:00
reply , err := s . client . ResponseWrapData ( ctx , & pb . ResponseWrapDataArgs {
2018-01-23 01:56:34 +00:00
Data : string ( buf [ : ] ) ,
2018-01-18 21:49:20 +00:00
TTL : int64 ( ttl ) ,
JWT : false ,
} )
if err != nil {
return nil , err
}
if reply . Err != "" {
return nil , errors . New ( reply . Err )
}
info , err := pb . ProtoResponseWrapInfoToLogicalResponseWrapInfo ( reply . WrapInfo )
if err != nil {
return nil , err
}
return info , nil
}
2022-02-17 14:50:33 +00:00
func ( s * gRPCSystemViewClient ) NewPluginClient ( ctx context . Context , config pluginutil . PluginClientConfig ) ( pluginutil . PluginClient , error ) {
return nil , fmt . Errorf ( "cannot call NewPluginClient from a plugin backend" )
}
2018-11-07 01:21:24 +00:00
func ( s * gRPCSystemViewClient ) LookupPlugin ( _ context . Context , _ string , _ consts . PluginType ) ( * pluginutil . PluginRunner , error ) {
2018-01-18 21:49:20 +00:00
return nil , fmt . Errorf ( "cannot call LookupPlugin from a plugin backend" )
}
2022-08-31 18:23:05 +00:00
func ( s * gRPCSystemViewClient ) LookupPluginVersion ( _ context . Context , _ string , _ consts . PluginType , _ string ) ( * pluginutil . PluginRunner , error ) {
return nil , fmt . Errorf ( "cannot call LookupPluginVersion from a plugin backend" )
}
2022-09-09 16:32:28 +00:00
func ( s * gRPCSystemViewClient ) ListVersionedPlugins ( _ context . Context , _ consts . PluginType ) ( [ ] pluginutil . VersionedPlugin , error ) {
return nil , fmt . Errorf ( "cannot call ListVersionedPlugins from a plugin backend" )
}
2018-01-18 21:49:20 +00:00
func ( s * gRPCSystemViewClient ) MlockEnabled ( ) bool {
reply , err := s . client . MlockEnabled ( context . Background ( ) , & pb . Empty { } )
if err != nil {
return false
}
return reply . Enabled
}
2018-09-18 03:03:00 +00:00
func ( s * gRPCSystemViewClient ) HasFeature ( feature license . Features ) bool {
// Not implemented
return false
}
2018-02-02 23:17:12 +00:00
func ( s * gRPCSystemViewClient ) LocalMount ( ) bool {
reply , err := s . client . LocalMount ( context . Background ( ) , & pb . Empty { } )
if err != nil {
return false
}
return reply . Local
}
2018-06-04 00:48:12 +00:00
func ( s * gRPCSystemViewClient ) EntityInfo ( entityID string ) ( * logical . Entity , error ) {
reply , err := s . client . EntityInfo ( context . Background ( ) , & pb . EntityInfoArgs {
EntityID : entityID ,
} )
if err != nil {
return nil , err
}
if reply . Err != "" {
return nil , errors . New ( reply . Err )
}
return reply . Entity , nil
}
2020-01-06 18:16:52 +00:00
func ( s * gRPCSystemViewClient ) GroupsForEntity ( entityID string ) ( [ ] * logical . Group , error ) {
reply , err := s . client . GroupsForEntity ( context . Background ( ) , & pb . EntityInfoArgs {
EntityID : entityID ,
} )
if err != nil {
return nil , err
}
if reply . Err != "" {
return nil , errors . New ( reply . Err )
}
return reply . Groups , nil
}
2018-08-03 16:32:17 +00:00
func ( s * gRPCSystemViewClient ) PluginEnv ( ctx context . Context ) ( * logical . PluginEnvironment , error ) {
reply , err := s . client . PluginEnv ( ctx , & pb . Empty { } )
if err != nil {
return nil , err
}
return reply . PluginEnvironment , nil
}
2022-12-07 18:29:51 +00:00
func ( s * gRPCSystemViewClient ) VaultVersion ( ctx context . Context ) ( string , error ) {
reply , err := s . client . PluginEnv ( ctx , & pb . Empty { } )
if err != nil {
return "" , err
}
return reply . PluginEnvironment . VaultVersion , nil
}
2020-05-27 18:28:00 +00:00
func ( s * gRPCSystemViewClient ) GeneratePasswordFromPolicy ( ctx context . Context , policyName string ) ( password string , err error ) {
req := & pb . GeneratePasswordFromPolicyRequest {
PolicyName : policyName ,
}
resp , err := s . client . GeneratePasswordFromPolicy ( ctx , req )
if err != nil {
return "" , err
}
return resp . Password , nil
}
Add path based primary write forwarding (PBPWF) - OSS (#18735)
* Add WriteForwardedStorage to sdk's plugin, logical in OSS
This should allow backends to specify paths to forward write
(storage.Put(...) and storage.Delete(...)) operations for.
Notably, these semantics are subject to change and shouldn't yet be
relied on.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Collect paths for write forwarding in OSS
This adds a path manager to Core, allowing tracking across all Vault
versions of paths which could use write forwarding if available. In
particular, even on OSS offerings, we'll need to template {{clusterId}}
into the paths, in the event of later upgrading to Enterprise. If we
didn't, we'd end up writing paths which will no longer be accessible
post-migration, due to write forwarding now replacing the sentinel with
the actual cluster identifier.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add forwarded writer implementation to OSS
Here, for paths given to us, we determine if we need to do cluster
translation and perform local writing. This is the OSS variant.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Wire up mount-specific request forwarding in OSS
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Clarify that state lock needs to be held to call HAState in OSS
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Move cluster sentinel constant to sdk/logical
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Expose ClusterID to Plugins via SystemView
This will let plugins learn what the Cluster's ID is, without having to
resort to hacks like writing a random string to its cluster-prefixed
namespace and then reading it once it has replicated.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add GRPC ClusterID implementation
For any external plugins which wish to use it.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
2023-01-20 21:36:18 +00:00
func ( s gRPCSystemViewClient ) ClusterID ( ctx context . Context ) ( string , error ) {
reply , err := s . client . ClusterInfo ( ctx , & pb . Empty { } )
if err != nil {
return "" , err
}
return reply . ClusterID , nil
}
2018-01-18 21:49:20 +00:00
type gRPCSystemViewServer struct {
2021-09-30 01:25:15 +00:00
pb . UnimplementedSystemViewServer
2018-01-18 21:49:20 +00:00
impl logical . SystemView
}
func ( s * gRPCSystemViewServer ) DefaultLeaseTTL ( ctx context . Context , _ * pb . Empty ) ( * pb . TTLReply , error ) {
2022-12-02 18:12:05 +00:00
if s . impl == nil {
return nil , errMissingSystemView
}
2018-01-18 21:49:20 +00:00
ttl := s . impl . DefaultLeaseTTL ( )
return & pb . TTLReply {
TTL : int64 ( ttl ) ,
} , nil
}
func ( s * gRPCSystemViewServer ) MaxLeaseTTL ( ctx context . Context , _ * pb . Empty ) ( * pb . TTLReply , error ) {
2022-12-02 18:12:05 +00:00
if s . impl == nil {
return nil , errMissingSystemView
}
2018-01-18 21:49:20 +00:00
ttl := s . impl . MaxLeaseTTL ( )
return & pb . TTLReply {
TTL : int64 ( ttl ) ,
} , nil
}
func ( s * gRPCSystemViewServer ) Tainted ( ctx context . Context , _ * pb . Empty ) ( * pb . TaintedReply , error ) {
2022-12-02 18:12:05 +00:00
if s . impl == nil {
return nil , errMissingSystemView
}
2018-01-18 21:49:20 +00:00
tainted := s . impl . Tainted ( )
return & pb . TaintedReply {
Tainted : tainted ,
} , nil
}
func ( s * gRPCSystemViewServer ) CachingDisabled ( ctx context . Context , _ * pb . Empty ) ( * pb . CachingDisabledReply , error ) {
2022-12-02 18:12:05 +00:00
if s . impl == nil {
return nil , errMissingSystemView
}
2018-01-18 21:49:20 +00:00
cachingDisabled := s . impl . CachingDisabled ( )
return & pb . CachingDisabledReply {
Disabled : cachingDisabled ,
} , nil
}
func ( s * gRPCSystemViewServer ) ReplicationState ( ctx context . Context , _ * pb . Empty ) ( * pb . ReplicationStateReply , error ) {
2022-12-02 18:12:05 +00:00
if s . impl == nil {
return nil , errMissingSystemView
}
2018-01-18 21:49:20 +00:00
replicationState := s . impl . ReplicationState ( )
return & pb . ReplicationStateReply {
State : int32 ( replicationState ) ,
} , nil
}
func ( s * gRPCSystemViewServer ) ResponseWrapData ( ctx context . Context , args * pb . ResponseWrapDataArgs ) ( * pb . ResponseWrapDataReply , error ) {
2022-12-02 18:12:05 +00:00
if s . impl == nil {
return nil , errMissingSystemView
}
2018-01-18 21:49:20 +00:00
data := map [ string ] interface { } { }
2018-01-23 01:56:34 +00:00
err := json . Unmarshal ( [ ] byte ( args . Data ) , & data )
2018-01-18 21:49:20 +00:00
if err != nil {
return & pb . ResponseWrapDataReply { } , err
}
// Do not allow JWTs to be returned
2018-01-19 06:44:44 +00:00
info , err := s . impl . ResponseWrapData ( ctx , data , time . Duration ( args . TTL ) , false )
2018-01-18 21:49:20 +00:00
if err != nil {
return & pb . ResponseWrapDataReply {
Err : pb . ErrToString ( err ) ,
} , nil
}
pbInfo , err := pb . LogicalResponseWrapInfoToProtoResponseWrapInfo ( info )
if err != nil {
return & pb . ResponseWrapDataReply { } , err
}
return & pb . ResponseWrapDataReply {
WrapInfo : pbInfo ,
} , nil
}
func ( s * gRPCSystemViewServer ) MlockEnabled ( ctx context . Context , _ * pb . Empty ) ( * pb . MlockEnabledReply , error ) {
2022-12-02 18:12:05 +00:00
if s . impl == nil {
return nil , errMissingSystemView
}
2018-01-18 21:49:20 +00:00
enabled := s . impl . MlockEnabled ( )
return & pb . MlockEnabledReply {
Enabled : enabled ,
} , nil
}
2018-02-02 23:17:12 +00:00
func ( s * gRPCSystemViewServer ) LocalMount ( ctx context . Context , _ * pb . Empty ) ( * pb . LocalMountReply , error ) {
2022-12-02 18:12:05 +00:00
if s . impl == nil {
return nil , errMissingSystemView
}
2018-02-02 23:17:12 +00:00
local := s . impl . LocalMount ( )
return & pb . LocalMountReply {
Local : local ,
} , nil
}
2018-06-04 00:48:12 +00:00
func ( s * gRPCSystemViewServer ) EntityInfo ( ctx context . Context , args * pb . EntityInfoArgs ) ( * pb . EntityInfoReply , error ) {
2022-12-02 18:12:05 +00:00
if s . impl == nil {
return nil , errMissingSystemView
}
2018-06-04 00:48:12 +00:00
entity , err := s . impl . EntityInfo ( args . EntityID )
if err != nil {
return & pb . EntityInfoReply {
Err : pb . ErrToString ( err ) ,
} , nil
}
return & pb . EntityInfoReply {
Entity : entity ,
} , nil
}
2018-08-03 16:32:17 +00:00
2020-01-06 18:16:52 +00:00
func ( s * gRPCSystemViewServer ) GroupsForEntity ( ctx context . Context , args * pb . EntityInfoArgs ) ( * pb . GroupsForEntityReply , error ) {
2022-12-02 18:12:05 +00:00
if s . impl == nil {
return nil , errMissingSystemView
}
2020-01-06 18:16:52 +00:00
groups , err := s . impl . GroupsForEntity ( args . EntityID )
if err != nil {
return & pb . GroupsForEntityReply {
Err : pb . ErrToString ( err ) ,
} , nil
}
return & pb . GroupsForEntityReply {
Groups : groups ,
} , nil
}
2018-08-03 16:32:17 +00:00
func ( s * gRPCSystemViewServer ) PluginEnv ( ctx context . Context , _ * pb . Empty ) ( * pb . PluginEnvReply , error ) {
2022-12-02 18:12:05 +00:00
if s . impl == nil {
return nil , errMissingSystemView
}
2018-08-03 16:32:17 +00:00
pluginEnv , err := s . impl . PluginEnv ( ctx )
if err != nil {
return & pb . PluginEnvReply {
Err : pb . ErrToString ( err ) ,
} , nil
}
return & pb . PluginEnvReply {
PluginEnvironment : pluginEnv ,
} , nil
}
2020-05-27 18:28:00 +00:00
func ( s * gRPCSystemViewServer ) GeneratePasswordFromPolicy ( ctx context . Context , req * pb . GeneratePasswordFromPolicyRequest ) ( * pb . GeneratePasswordFromPolicyReply , error ) {
2022-12-02 18:12:05 +00:00
if s . impl == nil {
return nil , errMissingSystemView
}
2020-05-27 18:28:00 +00:00
policyName := req . PolicyName
if policyName == "" {
return & pb . GeneratePasswordFromPolicyReply { } , status . Errorf ( codes . InvalidArgument , "no password policy specified" )
}
password , err := s . impl . GeneratePasswordFromPolicy ( ctx , policyName )
if err != nil {
return & pb . GeneratePasswordFromPolicyReply { } , status . Errorf ( codes . Internal , "failed to generate password" )
}
resp := & pb . GeneratePasswordFromPolicyReply {
Password : password ,
}
return resp , nil
}
Add path based primary write forwarding (PBPWF) - OSS (#18735)
* Add WriteForwardedStorage to sdk's plugin, logical in OSS
This should allow backends to specify paths to forward write
(storage.Put(...) and storage.Delete(...)) operations for.
Notably, these semantics are subject to change and shouldn't yet be
relied on.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Collect paths for write forwarding in OSS
This adds a path manager to Core, allowing tracking across all Vault
versions of paths which could use write forwarding if available. In
particular, even on OSS offerings, we'll need to template {{clusterId}}
into the paths, in the event of later upgrading to Enterprise. If we
didn't, we'd end up writing paths which will no longer be accessible
post-migration, due to write forwarding now replacing the sentinel with
the actual cluster identifier.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add forwarded writer implementation to OSS
Here, for paths given to us, we determine if we need to do cluster
translation and perform local writing. This is the OSS variant.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Wire up mount-specific request forwarding in OSS
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Clarify that state lock needs to be held to call HAState in OSS
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Move cluster sentinel constant to sdk/logical
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Expose ClusterID to Plugins via SystemView
This will let plugins learn what the Cluster's ID is, without having to
resort to hacks like writing a random string to its cluster-prefixed
namespace and then reading it once it has replicated.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add GRPC ClusterID implementation
For any external plugins which wish to use it.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
2023-01-20 21:36:18 +00:00
func ( s * gRPCSystemViewServer ) ClusterInfo ( ctx context . Context , _ * pb . Empty ) ( * pb . ClusterInfoReply , error ) {
if s . impl == nil {
return nil , errMissingSystemView
}
clusterId , err := s . impl . ClusterID ( ctx )
if err != nil {
return & pb . ClusterInfoReply { } , status . Errorf ( codes . Internal , "failed to fetch cluster id" )
}
return & pb . ClusterInfoReply {
ClusterID : clusterId ,
} , nil
}