Secretless Plugin Interface SDK Reference

The Secretless Plugin Interface SDK includes a set of pre-populated templates for HTTP and TCP Plugins that you can copy to simplify the process of creating plugins.

After determining the type of service to which you'll connect, and copying the appropriate templates to a new folder on your local machine, you only need to edit the settings of the following two methods: PluginInfo() and Connect() in order to create a plugin. Step-by-step instructions for creating plugins can be found in Create Secretless Connector Plugins.

The templates contain all of the necessary code, and for most use cases, there is no need to modify these settings. If however, you do need to make changes for your environment, this topic provides more information on each API element, and the special-purpose utilities, which are provided for your convenience.

API elements

Each API element in the Secretless Connector Plugin templates is described in below.

PluginInfo()

This top level function is always required. It returns basic information about your plugin and has the following signature:

 
func PluginInfo() map[string]string

The returned map must have the following keys:

Key

Description

pluginAPIVersion

The version of the Secretless plugin API that your plugin is written for. This allows the Secretless plugin API to change over time without breaking plugins.

type

This must be either connector.tcp or connector.http .

id

A short, clear, unique name for use in logs and the secretless.yml config file.

Allowed characters are: lowercase letters, _, : , - , and ~ .

For more information on the secretless.yml config file, see Secretless Configuration.

description

A short summary of the plugin, not to exceed 100 characters. This may be used in the future by the Secretless command line tool to list available plugins.

NewConnector

Both the tcp.Plugin and http.Plugin interfaces require that you implement the NewConnector method. NewConnector returns a Connector , a single-method interface that performs the actual authentication. The method signature is slightly different depending whether you're implementing a TCP or HTTP Connector .

When Secretless runs, it calls NewConnector once, and holds onto the returned Connector . That Connector is called each time a new client connection requires authentication.

Both NewConnector methods take only one argument — connector.Resources — which is described in connector.Resources below. The real work is done by the Connector functions that NewConnector returns.

TCP Connector

This is the single-method interface returned by the tcp.Plugin NewConnector() , and it's where your TCP authentication logic lives. The method's signature is:

 
func(net.Conn, connector.CredentialValuesByID) (net.Conn, error)

It is passed the client's net.Conn and the current CredentialValuesById , and returns an authenticated net.Conn to the target service. The authentication stage is complete after Connector is called.

Secretless now has both the client connection and an authenticated connection to the target service. The relationship between the client connection, Secretless, and the authenticated target service connection looks like this:

At this point, Secretless becomes an invisible proxy, streaming bytes back and forth between the client and target service, as if they are directly connected.

HTTP Connector

This is the single-method interface returned by the http.Plugin NewConnector() , and it's where the http authentication logic lives. The method's signature is:

 
func(*http.Request, connector.CredentialValuesById) error

This method is passed a pointer to an http.Request and the current CredentialValuesById, and is expected to alter that request so it contains the necessary authentication information. Typically, this means adding the appropriate headers to a request, for example, an Authorization header containing a Token, or a header containing an API key.

Since HTTP is a stateless protocol, Secretless calls this function every time a client sends an HTTP request to the target server, so that every request is authenticated.

API utilities

When implementing http.Connector or tcp.Connector interfaces, Secretless provides several tools that you may find useful, including: connector.Resources (including access to a secretless.Logger object) and connector.CredentialValuesByIds.

connector.Resources

Everything that your Connector needs from the Secretless framework is exposed through the connector.Resources interface, which is passed to your plugin's constructor.

You need to retain a reference to connector.Resources , via a closure, inside the Connector function returned by your constructor. The connector.Resources interface appears as follows:

 
package connector

type Resources interface {
  Config()          []byte
  Logger()          secretless.Logger
}

Config() provides you with the resources specified in the config section of your user's secretless.yml file (see Secretless Configuration for more information).

Logger() provides a basic logger that you can use for debugging and informational logging purposes (see secretless.Logger Interface below).

Following is a breakdown of each method:

Method

Description

Config()

Some connectors require additional, connector-specific configuration. Anything specified in your connector's config section is passed back via this method as a raw []byte . Your code is responsible for casting those bytes back into a meaningful struct that your code can work with.

Logger()

 

Returns an object similar to the standard library's log.Logger . This lets you log events to stdout and stderr . It respects Secretless's command line debug flag, so that calling Debugf or Infof does nothing unless you started Secretless in debug mode. See secretless.Logger Interface below for details.

secretless.Logger Interface

Your code should never use the fmt or log packages, or write directly to stdout or stderr. Instead, call Logger() on your connector.Resources to get a secretless.Logger with the following interface:

 
type Logger interface {
  Debugf(format string, v ...interface{})
  Debug(msg string)
  Debugln(msg string)

  Infof(format string, v ...interface{})
  Info(msg string)
  Infoln(msg string)

  Warnf(format string, v ...interface{})
  Warn(msg string)
  Warnln(msg string)

  Errorf(format string, v ...interface{})
  Error(msg string)
  Errorln(msg string)

  Fatalf(format string, v ...interface{})
  Fatal(msg string)
  Fatalln(msg string)
}

Following is a description of secretless.Logger methods:

Method

Description

Debug and Info

All Debug and Info methods do nothing unless Secretless is started with the Debugcommand line flag set to true. If Secretless is started in debug mode, Debug and Info methods write to stdout .

Warn, Error, and Fatal

The Warn, Error, and Fatal methods all write to stderr, regardless of the current Debug mode.

 

All Fatal methods call os.Exit(1) after printing their message.

The Logger automatically prepends the name of the currently-running service (i.e., the service name specified in your secretless.yml file) to all messages. For example, if your secretless.yml looks like this:

 
version: "v2"
services:
  sample-service:
    protocol: pg
    listenOn: unix:///sock/.s.PGSQL.5432
    ...

the Logger prepends sample-service to all messages.

Example

An example of a Secretless Connector Plugin that implements this interface is located in GitHub at secretless-broker/test/plugin/.