2026-04-06 15:48:37 +05:30
|
|
|
// Copyright IBM Corp. 2020, 2026
|
2021-10-14 11:56:08 -04:00
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
2023-02-02 17:15:17 -08:00
|
|
|
|
2023-04-08 16:15:14 -07:00
|
|
|
package external_plugins
|
2021-10-14 11:56:08 -04:00
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
2023-04-08 16:15:14 -07:00
|
|
|
"errors"
|
2021-10-14 11:56:08 -04:00
|
|
|
"fmt"
|
2022-12-06 12:25:27 -08:00
|
|
|
"os"
|
2021-10-14 11:56:08 -04:00
|
|
|
"os/exec"
|
2022-12-06 12:25:27 -08:00
|
|
|
"os/signal"
|
|
|
|
|
"syscall"
|
2021-10-14 11:56:08 -04:00
|
|
|
|
2026-10-12 10:33:41 -07:00
|
|
|
pb "repo.anhonesthost.net/CyberCoveLLC/threshold/sdk/pbs/plugin"
|
2021-10-14 11:56:08 -04:00
|
|
|
"github.com/hashicorp/go-plugin"
|
|
|
|
|
"google.golang.org/grpc"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
const (
|
2023-04-08 16:15:14 -07:00
|
|
|
hostServicePluginSetName = "host-plugin"
|
|
|
|
|
storageServicePluginSetName = "storage-plugin"
|
2021-10-14 11:56:08 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// HandshakeConfig is a shared config that can be used regardless of plugin, to
|
|
|
|
|
// avoid having to know type-specific things about each plugin
|
|
|
|
|
var HandshakeConfig = plugin.HandshakeConfig{
|
2023-04-08 16:15:14 -07:00
|
|
|
MagicCookieKey: "HASHICORP_BOUNDARY_PLUGIN",
|
|
|
|
|
MagicCookieValue: "boundary-plugin",
|
2021-10-14 11:56:08 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ServeHostPlugin is a generic function to start serving a host plugin service as a
|
|
|
|
|
// plugin
|
2023-04-08 16:15:14 -07:00
|
|
|
func ServePlugin(svc any, opt ...Option) error {
|
2021-10-14 11:56:08 -04:00
|
|
|
opts, err := getOpts(opt...)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2022-12-06 12:25:27 -08:00
|
|
|
|
|
|
|
|
signalCh := make(chan os.Signal, 1)
|
|
|
|
|
signal.Notify(signalCh, syscall.SIGHUP)
|
|
|
|
|
go func() {
|
|
|
|
|
for {
|
|
|
|
|
<-signalCh
|
|
|
|
|
}
|
|
|
|
|
}()
|
|
|
|
|
|
2023-04-08 16:15:14 -07:00
|
|
|
plugins := make(map[string]plugin.Plugin)
|
|
|
|
|
if hostSvc, ok := svc.(pb.HostPluginServiceServer); ok {
|
|
|
|
|
hostServiceServer, err := NewHostPluginServiceServer(hostSvc)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
plugins[hostServicePluginSetName] = hostServiceServer
|
2021-10-14 11:56:08 -04:00
|
|
|
}
|
2023-04-08 16:15:14 -07:00
|
|
|
if storageSvc, ok := svc.(pb.StoragePluginServiceServer); ok {
|
|
|
|
|
storageServiceServer, err := NewStoragePluginServiceServer(storageSvc)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
plugins[storageServicePluginSetName] = storageServiceServer
|
|
|
|
|
}
|
|
|
|
|
if len(plugins) == 0 {
|
|
|
|
|
return errors.New("no valid plugin server provided")
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-14 11:56:08 -04:00
|
|
|
plugin.Serve(&plugin.ServeConfig{
|
|
|
|
|
HandshakeConfig: HandshakeConfig,
|
|
|
|
|
VersionedPlugins: map[int]plugin.PluginSet{
|
2023-04-08 16:15:14 -07:00
|
|
|
1: plugins,
|
2021-10-14 11:56:08 -04:00
|
|
|
},
|
|
|
|
|
Logger: opts.withLogger,
|
|
|
|
|
GRPCServer: plugin.DefaultGRPCServer,
|
|
|
|
|
})
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-08 16:15:14 -07:00
|
|
|
func NewPluginClient(pluginPath, setName string, opt ...Option) (*plugin.Client, error) {
|
2021-10-14 11:56:08 -04:00
|
|
|
opts, err := getOpts(opt...)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2023-04-08 16:15:14 -07:00
|
|
|
|
|
|
|
|
var set plugin.PluginSet
|
|
|
|
|
switch setName {
|
|
|
|
|
case hostServicePluginSetName:
|
|
|
|
|
set = plugin.PluginSet{hostServicePluginSetName: &hostPlugin{}}
|
|
|
|
|
case storageServicePluginSetName:
|
|
|
|
|
set = plugin.PluginSet{storageServicePluginSetName: &storagePlugin{}}
|
|
|
|
|
}
|
2021-10-14 11:56:08 -04:00
|
|
|
|
|
|
|
|
return plugin.NewClient(&plugin.ClientConfig{
|
|
|
|
|
HandshakeConfig: HandshakeConfig,
|
|
|
|
|
VersionedPlugins: map[int]plugin.PluginSet{
|
2023-04-08 16:15:14 -07:00
|
|
|
1: set,
|
2021-10-14 11:56:08 -04:00
|
|
|
},
|
|
|
|
|
Cmd: exec.Command(pluginPath),
|
|
|
|
|
AllowedProtocols: []plugin.Protocol{
|
|
|
|
|
plugin.ProtocolGRPC,
|
|
|
|
|
},
|
|
|
|
|
Logger: opts.withLogger,
|
|
|
|
|
AutoMTLS: true,
|
|
|
|
|
}), nil
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-08 16:15:14 -07:00
|
|
|
type hostPlugin struct {
|
|
|
|
|
plugin.Plugin
|
|
|
|
|
|
|
|
|
|
impl pb.HostPluginServiceServer
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewHostPluginServiceServer(impl pb.HostPluginServiceServer) (*hostPlugin, error) {
|
|
|
|
|
if impl == nil {
|
|
|
|
|
return nil, fmt.Errorf("empty underlying host plugin passed in")
|
|
|
|
|
}
|
|
|
|
|
return &hostPlugin{
|
|
|
|
|
impl: impl,
|
|
|
|
|
}, nil
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-14 11:56:08 -04:00
|
|
|
func (h *hostPlugin) GRPCServer(broker *plugin.GRPCBroker, s *grpc.Server) error {
|
|
|
|
|
pb.RegisterHostPluginServiceServer(s, h.impl)
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-25 18:29:38 -05:00
|
|
|
func (h *hostPlugin) GRPCClient(ctx context.Context, broker *plugin.GRPCBroker, c *grpc.ClientConn) (any, error) {
|
2021-10-14 11:56:08 -04:00
|
|
|
return pb.NewHostPluginServiceClient(c), nil
|
|
|
|
|
}
|
2023-04-08 16:15:14 -07:00
|
|
|
|
|
|
|
|
type storagePlugin struct {
|
|
|
|
|
plugin.Plugin
|
|
|
|
|
|
|
|
|
|
impl pb.StoragePluginServiceServer
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewStoragePluginServiceServer(impl pb.StoragePluginServiceServer) (*storagePlugin, error) {
|
|
|
|
|
if impl == nil {
|
|
|
|
|
return nil, fmt.Errorf("empty underlying storage plugin passed in")
|
|
|
|
|
}
|
|
|
|
|
return &storagePlugin{
|
|
|
|
|
impl: impl,
|
|
|
|
|
}, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *storagePlugin) GRPCServer(broker *plugin.GRPCBroker, s *grpc.Server) error {
|
|
|
|
|
pb.RegisterStoragePluginServiceServer(s, p.impl)
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *storagePlugin) GRPCClient(ctx context.Context, broker *plugin.GRPCBroker, c *grpc.ClientConn) (any, error) {
|
|
|
|
|
return pb.NewStoragePluginServiceClient(c), nil
|
|
|
|
|
}
|