mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-11-01 19:17:58 +00:00
move system view interface, grpc server, and client to stubs_oss files (#29291)
This commit is contained in:
@@ -231,9 +231,6 @@ func (b *backendGRPCPluginClient) Setup(ctx context.Context, config *logical.Bac
|
|||||||
if b.metadataMode {
|
if b.metadataMode {
|
||||||
sysViewImpl = &logical.StaticSystemView{}
|
sysViewImpl = &logical.StaticSystemView{}
|
||||||
}
|
}
|
||||||
sysView := &gRPCSystemViewServer{
|
|
||||||
impl: sysViewImpl,
|
|
||||||
}
|
|
||||||
|
|
||||||
events := &GRPCEventsServer{
|
events := &GRPCEventsServer{
|
||||||
impl: config.EventsSender,
|
impl: config.EventsSender,
|
||||||
@@ -245,7 +242,7 @@ func (b *backendGRPCPluginClient) Setup(ctx context.Context, config *logical.Bac
|
|||||||
opts = append(opts, grpc.MaxSendMsgSize(math.MaxInt32))
|
opts = append(opts, grpc.MaxSendMsgSize(math.MaxInt32))
|
||||||
|
|
||||||
s := grpc.NewServer(opts...)
|
s := grpc.NewServer(opts...)
|
||||||
pb.RegisterSystemViewServer(s, sysView)
|
registerSystemViewServer(s, sysViewImpl, config)
|
||||||
pb.RegisterStorageServer(s, storage)
|
pb.RegisterStorageServer(s, storage)
|
||||||
pb.RegisterEventsServer(s, events)
|
pb.RegisterEventsServer(s, events)
|
||||||
b.server.Store(s)
|
b.server.Store(s)
|
||||||
|
|||||||
20
sdk/plugin/grpc_backend_client_stubs_oss.go
Normal file
20
sdk/plugin/grpc_backend_client_stubs_oss.go
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
// Copyright (c) HashiCorp, Inc.
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
//go:build !enterprise
|
||||||
|
|
||||||
|
package plugin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/hashicorp/vault/sdk/logical"
|
||||||
|
"github.com/hashicorp/vault/sdk/plugin/pb"
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
// registerSystemViewServer (Vault Community edition) registers the SystemView server
|
||||||
|
// to the gRPC service registrar
|
||||||
|
func registerSystemViewServer(s *grpc.Server, sysView logical.SystemView, _ *logical.BackendConfig) {
|
||||||
|
pb.RegisterSystemViewServer(s, &gRPCSystemViewServer{
|
||||||
|
impl: sysView,
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -94,13 +94,12 @@ func (b *backendGRPCPluginServer) Setup(ctx context.Context, args *pb.SetupArgs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
storage := newGRPCStorageClient(brokeredClient)
|
storage := newGRPCStorageClient(brokeredClient)
|
||||||
sysView := newGRPCSystemView(brokeredClient)
|
|
||||||
events := newGRPCEventsClient(brokeredClient)
|
events := newGRPCEventsClient(brokeredClient)
|
||||||
|
|
||||||
config := &logical.BackendConfig{
|
config := &logical.BackendConfig{
|
||||||
StorageView: storage,
|
StorageView: storage,
|
||||||
Logger: b.logger,
|
Logger: b.logger,
|
||||||
System: sysView,
|
System: newGRPCSystemViewFromSetupArgs(brokeredClient, args),
|
||||||
Config: args.Config,
|
Config: args.Config,
|
||||||
BackendUUID: args.BackendUUID,
|
BackendUUID: args.BackendUUID,
|
||||||
EventsSender: events,
|
EventsSender: events,
|
||||||
|
|||||||
17
sdk/plugin/grpc_backend_server_stubs_oss.go
Normal file
17
sdk/plugin/grpc_backend_server_stubs_oss.go
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
// Copyright (c) HashiCorp, Inc.
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
//go:build !enterprise
|
||||||
|
|
||||||
|
package plugin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/hashicorp/vault/sdk/logical"
|
||||||
|
"github.com/hashicorp/vault/sdk/plugin/pb"
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
// newGRPCSystemViewFromSetupArgs (Vault Community edition) constructs a gRPC SystemView client.
|
||||||
|
func newGRPCSystemViewFromSetupArgs(conn *grpc.ClientConn, _ *pb.SetupArgs) logical.SystemView {
|
||||||
|
return newGRPCSystemView(conn)
|
||||||
|
}
|
||||||
@@ -34,140 +34,6 @@ type dynamicSystemView struct {
|
|||||||
perfStandby bool
|
perfStandby bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type extendedSystemView interface {
|
|
||||||
logical.SystemView
|
|
||||||
logical.ExtendedSystemView
|
|
||||||
// SudoPrivilege won't work over the plugin system so we keep it here
|
|
||||||
// instead of in sdk/logical to avoid exposing to plugins
|
|
||||||
SudoPrivilege(context.Context, string, string) bool
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ logical.ExtendedSystemView = (*extendedSystemViewImpl)(nil)
|
|
||||||
|
|
||||||
type extendedSystemViewImpl struct {
|
|
||||||
dynamicSystemView
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e extendedSystemViewImpl) Auditor() logical.Auditor {
|
|
||||||
return genericAuditor{
|
|
||||||
mountType: e.mountEntry.Type,
|
|
||||||
namespace: e.mountEntry.Namespace(),
|
|
||||||
c: e.core,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e extendedSystemViewImpl) ForwardGenericRequest(ctx context.Context, req *logical.Request) (*logical.Response, error) {
|
|
||||||
// Forward the request if allowed
|
|
||||||
if couldForward(e.core) {
|
|
||||||
ctx = namespace.ContextWithNamespace(ctx, e.mountEntry.Namespace())
|
|
||||||
ctx = logical.IndexStateContext(ctx, &logical.WALState{})
|
|
||||||
ctx = context.WithValue(ctx, ctxKeyForwardedRequestMountAccessor{}, e.mountEntry.Accessor)
|
|
||||||
return forward(ctx, e.core, req)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, logical.ErrReadOnly
|
|
||||||
}
|
|
||||||
|
|
||||||
// SudoPrivilege returns true if given path has sudo privileges
|
|
||||||
// for the given client token
|
|
||||||
func (e extendedSystemViewImpl) SudoPrivilege(ctx context.Context, path string, token string) bool {
|
|
||||||
// Resolve the token policy
|
|
||||||
te, err := e.core.tokenStore.Lookup(ctx, token)
|
|
||||||
if err != nil {
|
|
||||||
e.core.logger.Error("failed to lookup sudo token", "error", err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure the token is valid
|
|
||||||
if te == nil {
|
|
||||||
e.core.logger.Error("entry not found for given token")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
policyNames := make(map[string][]string)
|
|
||||||
// Add token policies
|
|
||||||
policyNames[te.NamespaceID] = append(policyNames[te.NamespaceID], te.Policies...)
|
|
||||||
|
|
||||||
tokenNS, err := NamespaceByID(ctx, te.NamespaceID, e.core)
|
|
||||||
if err != nil {
|
|
||||||
e.core.logger.Error("failed to lookup token namespace", "error", err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if tokenNS == nil {
|
|
||||||
e.core.logger.Error("failed to lookup token namespace", "error", namespace.ErrNoNamespace)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add identity policies from all the namespaces
|
|
||||||
entity, identityPolicies, err := e.core.fetchEntityAndDerivedPolicies(ctx, tokenNS, te.EntityID, te.NoIdentityPolicies)
|
|
||||||
if err != nil {
|
|
||||||
e.core.logger.Error("failed to fetch identity policies", "error", err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
for nsID, nsPolicies := range identityPolicies {
|
|
||||||
policyNames[nsID] = append(policyNames[nsID], nsPolicies...)
|
|
||||||
}
|
|
||||||
|
|
||||||
tokenCtx := namespace.ContextWithNamespace(ctx, tokenNS)
|
|
||||||
|
|
||||||
// Add the inline policy if it's set
|
|
||||||
policies := make([]*Policy, 0)
|
|
||||||
if te.InlinePolicy != "" {
|
|
||||||
inlinePolicy, err := ParseACLPolicy(tokenNS, te.InlinePolicy)
|
|
||||||
if err != nil {
|
|
||||||
e.core.logger.Error("failed to parse the token's inline policy", "error", err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
policies = append(policies, inlinePolicy)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Construct the corresponding ACL object. Derive and use a new context that
|
|
||||||
// uses the req.ClientToken's namespace
|
|
||||||
acl, err := e.core.policyStore.ACL(tokenCtx, entity, policyNames, policies...)
|
|
||||||
if err != nil {
|
|
||||||
e.core.logger.Error("failed to retrieve ACL for token's policies", "token_policies", te.Policies, "error", err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// The operation type isn't important here as this is run from a path the
|
|
||||||
// user has already been given access to; we only care about whether they
|
|
||||||
// have sudo. Note that we use root context because the path that comes in
|
|
||||||
// must be fully-qualified already so we don't want AllowOperation to
|
|
||||||
// prepend a namespace prefix onto it.
|
|
||||||
req := new(logical.Request)
|
|
||||||
req.Operation = logical.ReadOperation
|
|
||||||
req.Path = path
|
|
||||||
authResults := acl.AllowOperation(namespace.RootContext(ctx), req, true)
|
|
||||||
return authResults.RootPrivs
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e extendedSystemViewImpl) APILockShouldBlockRequest() (bool, error) {
|
|
||||||
mountEntry := e.mountEntry
|
|
||||||
if mountEntry == nil {
|
|
||||||
return false, fmt.Errorf("no mount entry")
|
|
||||||
}
|
|
||||||
ns := mountEntry.Namespace()
|
|
||||||
|
|
||||||
if err := e.core.entBlockRequestIfError(ns.Path, mountEntry.Path); err != nil {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e extendedSystemViewImpl) RequestWellKnownRedirect(ctx context.Context, src, dest string) error {
|
|
||||||
return e.core.WellKnownRedirects.TryRegister(ctx, e.core, e.mountEntry.UUID, src, dest)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e extendedSystemViewImpl) DeregisterWellKnownRedirect(ctx context.Context, src string) bool {
|
|
||||||
return e.core.WellKnownRedirects.DeregisterSource(e.mountEntry.UUID, src)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetPinnedPluginVersion implements logical.ExtendedSystemView.
|
|
||||||
func (e extendedSystemViewImpl) GetPinnedPluginVersion(ctx context.Context, pluginType consts.PluginType, pluginName string) (*pluginutil.PinnedVersion, error) {
|
|
||||||
return e.core.pluginCatalog.GetPinnedVersion(ctx, pluginType, pluginName)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d dynamicSystemView) DefaultLeaseTTL() time.Duration {
|
func (d dynamicSystemView) DefaultLeaseTTL() time.Duration {
|
||||||
def, _ := d.fetchTTLs()
|
def, _ := d.fetchTTLs()
|
||||||
return def
|
return def
|
||||||
|
|||||||
140
vault/extended_system_view.go
Normal file
140
vault/extended_system_view.go
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
// Copyright (c) HashiCorp, Inc.
|
||||||
|
// SPDX-License-Identifier: BUSL-1.1
|
||||||
|
|
||||||
|
package vault
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/hashicorp/vault/helper/namespace"
|
||||||
|
"github.com/hashicorp/vault/sdk/helper/consts"
|
||||||
|
"github.com/hashicorp/vault/sdk/helper/pluginutil"
|
||||||
|
"github.com/hashicorp/vault/sdk/logical"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ logical.ExtendedSystemView = (*extendedSystemViewImpl)(nil)
|
||||||
|
|
||||||
|
type extendedSystemViewImpl struct {
|
||||||
|
dynamicSystemView
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e extendedSystemViewImpl) Auditor() logical.Auditor {
|
||||||
|
return genericAuditor{
|
||||||
|
mountType: e.mountEntry.Type,
|
||||||
|
namespace: e.mountEntry.Namespace(),
|
||||||
|
c: e.core,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e extendedSystemViewImpl) ForwardGenericRequest(ctx context.Context, req *logical.Request) (*logical.Response, error) {
|
||||||
|
// Forward the request if allowed
|
||||||
|
if couldForward(e.core) {
|
||||||
|
ctx = namespace.ContextWithNamespace(ctx, e.mountEntry.Namespace())
|
||||||
|
ctx = logical.IndexStateContext(ctx, &logical.WALState{})
|
||||||
|
ctx = context.WithValue(ctx, ctxKeyForwardedRequestMountAccessor{}, e.mountEntry.Accessor)
|
||||||
|
return forward(ctx, e.core, req)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, logical.ErrReadOnly
|
||||||
|
}
|
||||||
|
|
||||||
|
// SudoPrivilege returns true if given path has sudo privileges
|
||||||
|
// for the given client token
|
||||||
|
func (e extendedSystemViewImpl) SudoPrivilege(ctx context.Context, path string, token string) bool {
|
||||||
|
// Resolve the token policy
|
||||||
|
te, err := e.core.tokenStore.Lookup(ctx, token)
|
||||||
|
if err != nil {
|
||||||
|
e.core.logger.Error("failed to lookup sudo token", "error", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure the token is valid
|
||||||
|
if te == nil {
|
||||||
|
e.core.logger.Error("entry not found for given token")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
policyNames := make(map[string][]string)
|
||||||
|
// Add token policies
|
||||||
|
policyNames[te.NamespaceID] = append(policyNames[te.NamespaceID], te.Policies...)
|
||||||
|
|
||||||
|
tokenNS, err := NamespaceByID(ctx, te.NamespaceID, e.core)
|
||||||
|
if err != nil {
|
||||||
|
e.core.logger.Error("failed to lookup token namespace", "error", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if tokenNS == nil {
|
||||||
|
e.core.logger.Error("failed to lookup token namespace", "error", namespace.ErrNoNamespace)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add identity policies from all the namespaces
|
||||||
|
entity, identityPolicies, err := e.core.fetchEntityAndDerivedPolicies(ctx, tokenNS, te.EntityID, te.NoIdentityPolicies)
|
||||||
|
if err != nil {
|
||||||
|
e.core.logger.Error("failed to fetch identity policies", "error", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for nsID, nsPolicies := range identityPolicies {
|
||||||
|
policyNames[nsID] = append(policyNames[nsID], nsPolicies...)
|
||||||
|
}
|
||||||
|
|
||||||
|
tokenCtx := namespace.ContextWithNamespace(ctx, tokenNS)
|
||||||
|
|
||||||
|
// Add the inline policy if it's set
|
||||||
|
policies := make([]*Policy, 0)
|
||||||
|
if te.InlinePolicy != "" {
|
||||||
|
inlinePolicy, err := ParseACLPolicy(tokenNS, te.InlinePolicy)
|
||||||
|
if err != nil {
|
||||||
|
e.core.logger.Error("failed to parse the token's inline policy", "error", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
policies = append(policies, inlinePolicy)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct the corresponding ACL object. Derive and use a new context that
|
||||||
|
// uses the req.ClientToken's namespace
|
||||||
|
acl, err := e.core.policyStore.ACL(tokenCtx, entity, policyNames, policies...)
|
||||||
|
if err != nil {
|
||||||
|
e.core.logger.Error("failed to retrieve ACL for token's policies", "token_policies", te.Policies, "error", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// The operation type isn't important here as this is run from a path the
|
||||||
|
// user has already been given access to; we only care about whether they
|
||||||
|
// have sudo. Note that we use root context because the path that comes in
|
||||||
|
// must be fully-qualified already so we don't want AllowOperation to
|
||||||
|
// prepend a namespace prefix onto it.
|
||||||
|
req := new(logical.Request)
|
||||||
|
req.Operation = logical.ReadOperation
|
||||||
|
req.Path = path
|
||||||
|
authResults := acl.AllowOperation(namespace.RootContext(ctx), req, true)
|
||||||
|
return authResults.RootPrivs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e extendedSystemViewImpl) APILockShouldBlockRequest() (bool, error) {
|
||||||
|
mountEntry := e.mountEntry
|
||||||
|
if mountEntry == nil {
|
||||||
|
return false, fmt.Errorf("no mount entry")
|
||||||
|
}
|
||||||
|
ns := mountEntry.Namespace()
|
||||||
|
|
||||||
|
if err := e.core.entBlockRequestIfError(ns.Path, mountEntry.Path); err != nil {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e extendedSystemViewImpl) RequestWellKnownRedirect(ctx context.Context, src, dest string) error {
|
||||||
|
return e.core.WellKnownRedirects.TryRegister(ctx, e.core, e.mountEntry.UUID, src, dest)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e extendedSystemViewImpl) DeregisterWellKnownRedirect(ctx context.Context, src string) bool {
|
||||||
|
return e.core.WellKnownRedirects.DeregisterSource(e.mountEntry.UUID, src)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPinnedPluginVersion implements logical.ExtendedSystemView.
|
||||||
|
func (e extendedSystemViewImpl) GetPinnedPluginVersion(ctx context.Context, pluginType consts.PluginType, pluginName string) (*pluginutil.PinnedVersion, error) {
|
||||||
|
return e.core.pluginCatalog.GetPinnedVersion(ctx, pluginType, pluginName)
|
||||||
|
}
|
||||||
22
vault/extended_system_view_stubs_oss.go
Normal file
22
vault/extended_system_view_stubs_oss.go
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
// Copyright (c) HashiCorp, Inc.
|
||||||
|
// SPDX-License-Identifier: BUSL-1.1
|
||||||
|
|
||||||
|
//go:build !enterprise
|
||||||
|
|
||||||
|
package vault
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/hashicorp/vault/sdk/logical"
|
||||||
|
)
|
||||||
|
|
||||||
|
// extendedSystemView (Vault Community edition) is a logical.SystemView
|
||||||
|
// that is extended with logical.ExtendedSystemView and SudoPrivilege
|
||||||
|
type extendedSystemView interface {
|
||||||
|
logical.SystemView
|
||||||
|
logical.ExtendedSystemView
|
||||||
|
// SudoPrivilege won't work over the plugin system so we keep it here
|
||||||
|
// instead of in sdk/logical to avoid exposing to plugins
|
||||||
|
SudoPrivilege(context.Context, string, string) bool
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user