Plugin development
Advanced topic! Plugin development is a highly advanced topic in Vault, and is not required knowledge for day-to-day usage. If you don't plan on writing any plugins, we recommend not reading this section of the documentation.
Because Vault communicates to plugins over a RPC interface, you can build and distribute a plugin for Vault without having to rebuild Vault itself. This makes it easy for you to build a Vault plugin for your organization's internal use, for a proprietary API that you don't want to open source, or to prototype something before contributing it back to the main project.
In theory, because the plugin interface is HTTP, you could even develop a plugin using a completely different programming language! (Disclaimer, you would also have to re-implement the plugin API which is not a trivial amount of work.)
Developing a plugin is simple. The only knowledge necessary to write a plugin is basic command-line skills and basic knowledge of the Go programming language.
Your plugin implementation needs to satisfy the interface for the plugin type you want to build. You can find these definitions in the docs for the backend running the plugin.
Note: Plugins should be prepared to handle multiple concurrent requests from Vault.
Serving a plugin
Serving a plugin with multiplexing
Plugin multiplexing requires github.com/hashicorp/vault/sdk v0.5.4
or above.
The following code exhibits an example main package for a Vault plugin using the Vault SDK for a secrets engine or auth method:
package main import ( "os" myPlugin "your/plugin/import/path" "github.com/hashicorp/vault/api" "github.com/hashicorp/vault/sdk/plugin") func main() { apiClientMeta := &api.PluginAPIClientMeta{} flags := apiClientMeta.FlagSet() flags.Parse(os.Args[1:]) tlsConfig := apiClientMeta.GetTLSConfig() tlsProviderFunc := api.VaultPluginTLSProvider(tlsConfig) err := plugin.ServeMultiplex(&plugin.ServeOpts{ BackendFactoryFunc: myPlugin.Factory, TLSProviderFunc: tlsProviderFunc, }) if err != nil { logger := hclog.New(&hclog.LoggerOptions{}) logger.Error("plugin shutting down", "error", err) os.Exit(1) }}
And that's basically it! You would just need to change myPlugin
to your actual
plugin.
Plugin backwards compatibility with Vault
Let's take a closer look at a snippet from the above main package.
err := plugin.ServeMultiplex(&plugin.ServeOpts{ BackendFactoryFunc: myPlugin.Factory, TLSProviderFunc: tlsProviderFunc, })
The call to plugin.ServeMultiplex
ensures that the plugin will use
Vault's plugin
multiplexing feature.
However, this plugin will not be multiplexed if it is run by a version of Vault
that does not support multiplexing. Vault will simply fall back to a plugin
version that it can run. Additionally, we set the TLSProviderFunc
to ensure
that our plugin is backwards compatible with versions of Vault that do not
support automatic mutual TLS for secure plugin
communication. If you
are certain your plugin does not need backwards compatibility, this field can
be omitted.
Leveraging plugin versioning
Plugins can optionally self-report their own semantic version. For plugins that
do so, Vault will automatically populate the plugin's version in the catalog
without requiring the user to provide it. If users do provide a version during
registration, Vault will error if the version provided does not match what the
plugin reports. Plugins that report a non-empty version must report a valid
Semantic Version with a leading 'v' added or registration
will fail, e.g. v1.0.0
or v2.3.2-beta
.
Plugins that want to opt into this behavior can implement the version interface. However, it is not a prerequisite; users can still provide a version during registration if the plugin does not implement the version interface.
To implement the version interface, plugins should first upgrade the Vault SDK package to at least v0.6.0.
Auth and secrets plugins based on framework.Backend
from the SDK should set the
RunningVersion
variable, and the framework will implement the version interface.
Database plugins have a smaller API than framework.Backend
exposes, and should
instead implement the
PluginVersioner
interface directly.
Plugin logging
Auth and secrets plugins based on framework.Backend
from the SDK can take
advantage of the SDK's default logger.
No additional setup is required. The logger can be used like the following:
func (b *backend) example() { b.Logger().Trace("Trace level log") b.Logger().Debug("Debug level log") b.Logger().Info("Info level log") b.Logger().Warn("Warn level log") b.Logger().Error("Error level log")}
See the source code of vault-auth-plugin-example for a more complete example of a plugin using logging.
Building a plugin from source
To build a plugin from source, first navigate to the location holding the
desired plugin version. Next, run go build
to obtain a new binary for the
plugin. Finally,
register the
plugin and enable it.
Plugin development - resources
For more information on how to register and enable your plugin, refer to the Building Plugin Backends tutorial.
Other HashiCorp plugin development resources:
Plugin development - resources - community
See the Vault Integrations page to find Community plugin examples/guides developed by community members. HashiCorp does not validate these for correctness.