get.porter.sh/porter@v1.3.0/pkg/secrets/pluginstore/store.go (about)

     1  package pluginstore
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  
     8  	"get.porter.sh/porter/pkg/config"
     9  	"get.porter.sh/porter/pkg/plugins/pluggable"
    10  	"get.porter.sh/porter/pkg/secrets/plugins"
    11  	"get.porter.sh/porter/pkg/tracing"
    12  	"go.opentelemetry.io/otel/attribute"
    13  )
    14  
    15  var _ plugins.SecretsProtocol = &Store{}
    16  
    17  // Store is a plugin-backed source of secrets. It resolves the appropriate
    18  // plugin based on Porter's config and implements the plugins.SecretsProtocol interface
    19  // using the backing plugin.
    20  //
    21  // Connects just-in-time, but you must call Close to release resources.
    22  type Store struct {
    23  	*config.Config
    24  	plugin plugins.SecretsProtocol
    25  	conn   *pluggable.PluginConnection
    26  }
    27  
    28  func NewStore(c *config.Config) *Store {
    29  	return &Store{
    30  		Config: c,
    31  	}
    32  }
    33  
    34  // NewSecretsPluginConfig for secret sources.
    35  func NewSecretsPluginConfig() pluggable.PluginTypeConfig {
    36  	return pluggable.PluginTypeConfig{
    37  		Interface: plugins.PluginInterface,
    38  		Plugin:    &Plugin{},
    39  		GetDefaultPluggable: func(c *config.Config) string {
    40  			return c.Data.DefaultSecrets
    41  		},
    42  		GetPluggable: func(c *config.Config, name string) (pluggable.Entry, error) {
    43  			return c.GetSecretsPlugin(name)
    44  		},
    45  		GetDefaultPlugin: func(c *config.Config) string {
    46  			return c.Data.DefaultSecretsPlugin
    47  		},
    48  		ProtocolVersion: plugins.PluginProtocolVersion,
    49  	}
    50  }
    51  
    52  func (s *Store) Resolve(ctx context.Context, keyName string, keyValue string) (string, error) {
    53  	ctx, span := tracing.StartSpan(ctx,
    54  		attribute.String("keyName", keyName),
    55  		attribute.String("keyValue", keyValue))
    56  	defer span.EndSpan()
    57  
    58  	if err := s.Connect(ctx); err != nil {
    59  		return "", err
    60  	}
    61  
    62  	value, err := s.plugin.Resolve(ctx, keyName, keyValue)
    63  	if err != nil {
    64  		return "", span.Error(err)
    65  	}
    66  	return value, nil
    67  }
    68  
    69  func (s *Store) Create(ctx context.Context, keyName string, keyValue string, value string) error {
    70  	ctx, span := tracing.StartSpan(ctx,
    71  		attribute.String("keyName", keyName),
    72  		attribute.String("keyValue", keyValue))
    73  	defer span.EndSpan()
    74  
    75  	if err := s.Connect(ctx); err != nil {
    76  		return err
    77  	}
    78  
    79  	err := s.plugin.Create(ctx, keyName, keyValue, value)
    80  	if errors.Is(err, plugins.ErrNotImplemented) {
    81  		return span.Error(fmt.Errorf(`the current secrets plugin does not support persisting secrets. You need to edit your porter configuration file and configure a different secrets plugin. See https://porter.sh/end-users/configuration/#change-the-default-secrets-plugin for details: %w`, err))
    82  	}
    83  
    84  	return span.Error(err)
    85  }
    86  
    87  // Connect initializes the plugin for use.
    88  // The plugin itself is responsible for ensuring it was called.
    89  // Close is called automatically when the plugin is used by Porter.
    90  func (s *Store) Connect(ctx context.Context) error {
    91  	if s.plugin != nil {
    92  		return nil
    93  	}
    94  
    95  	ctx, span := tracing.StartSpan(ctx)
    96  	defer span.EndSpan()
    97  
    98  	pluginType := NewSecretsPluginConfig()
    99  
   100  	l := pluggable.NewPluginLoader(s.Config)
   101  	conn, err := l.Load(ctx, pluginType)
   102  	if err != nil {
   103  		return span.Error(err)
   104  	}
   105  	s.conn = conn
   106  
   107  	store, ok := conn.GetClient().(plugins.SecretsProtocol)
   108  	if !ok {
   109  		conn.Close(ctx)
   110  		return span.Error(fmt.Errorf("the interface (%T) exposed by the %s plugin was not plugins.SecretsProtocol", conn.GetClient(), conn))
   111  	}
   112  	s.plugin = store
   113  
   114  	return nil
   115  }
   116  
   117  func (s *Store) Close() error {
   118  	if s.conn != nil {
   119  		s.conn.Close(context.Background())
   120  		s.conn = nil
   121  	}
   122  	return nil
   123  }