Skip to content

Commit 909da77

Browse files
tomhjpMonkeychip
authored andcommitted
Support setting plugin TMPDIR in config as well as env (#24978)
1 parent 7c3f939 commit 909da77

16 files changed

+139
-38
lines changed

changelog/24978.txt

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:improvement
2+
core: Added new `plugin_tmpdir` config option for containerized plugins, in addition to the existing `VAULT_PLUGIN_TMPDIR` environment variable.
3+
```

command/commands.go

+3
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@ const (
9797
// logged at startup _per node_. This was initially introduced for the events
9898
// system being developed over multiple release cycles.
9999
EnvVaultExperiments = "VAULT_EXPERIMENTS"
100+
// EnvVaultPluginTmpdir sets the folder to use for Unix sockets when setting
101+
// up containerized plugins.
102+
EnvVaultPluginTmpdir = "VAULT_PLUGIN_TMPDIR"
100103

101104
// flagNameAddress is the flag used in the base command to read in the
102105
// address of the Vault server.

command/server.go

+5
Original file line numberDiff line numberDiff line change
@@ -1153,6 +1153,10 @@ func (c *ServerCommand) Run(args []string) int {
11531153
config.License = envLicense
11541154
}
11551155

1156+
if envPluginTmpdir := os.Getenv(EnvVaultPluginTmpdir); envPluginTmpdir != "" {
1157+
config.PluginTmpdir = envPluginTmpdir
1158+
}
1159+
11561160
if err := server.ExperimentsFromEnvAndCLI(config, EnvVaultExperiments, c.flagExperiments); err != nil {
11571161
c.UI.Error(err.Error())
11581162
return 1
@@ -3082,6 +3086,7 @@ func createCoreConfig(c *ServerCommand, config *server.Config, backend physical.
30823086
ClusterName: config.ClusterName,
30833087
CacheSize: config.CacheSize,
30843088
PluginDirectory: config.PluginDirectory,
3089+
PluginTmpdir: config.PluginTmpdir,
30853090
PluginFileUid: config.PluginFileUid,
30863091
PluginFilePermissions: config.PluginFilePermissions,
30873092
EnableUI: config.EnableUI,

command/server/config.go

+7
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ type Config struct {
6969
ClusterCipherSuites string `hcl:"cluster_cipher_suites"`
7070

7171
PluginDirectory string `hcl:"plugin_directory"`
72+
PluginTmpdir string `hcl:"plugin_tmpdir"`
7273

7374
PluginFileUid int `hcl:"plugin_file_uid"`
7475

@@ -363,6 +364,11 @@ func (c *Config) Merge(c2 *Config) *Config {
363364
result.PluginDirectory = c2.PluginDirectory
364365
}
365366

367+
result.PluginTmpdir = c.PluginTmpdir
368+
if c2.PluginTmpdir != "" {
369+
result.PluginTmpdir = c2.PluginTmpdir
370+
}
371+
366372
result.PluginFileUid = c.PluginFileUid
367373
if c2.PluginFileUid != 0 {
368374
result.PluginFileUid = c2.PluginFileUid
@@ -1114,6 +1120,7 @@ func (c *Config) Sanitized() map[string]interface{} {
11141120
"cluster_cipher_suites": c.ClusterCipherSuites,
11151121

11161122
"plugin_directory": c.PluginDirectory,
1123+
"plugin_tmpdir": c.PluginTmpdir,
11171124

11181125
"plugin_file_uid": c.PluginFileUid,
11191126

command/server/config_test_helpers.go

+4
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,9 @@ func testLoadConfigFile(t *testing.T) {
476476
EnableResponseHeaderRaftNodeIDRaw: true,
477477

478478
LicensePath: "/path/to/license",
479+
480+
PluginDirectory: "/path/to/plugins",
481+
PluginTmpdir: "/tmp/plugins",
479482
}
480483

481484
addExpectedEntConfig(expected, []string{})
@@ -802,6 +805,7 @@ func testConfig_Sanitized(t *testing.T) {
802805
"max_lease_ttl": (30 * 24 * time.Hour) / time.Second,
803806
"pid_file": "./pidfile",
804807
"plugin_directory": "",
808+
"plugin_tmpdir": "",
805809
"seals": []interface{}{
806810
map[string]interface{}{
807811
"disabled": false,

command/server/test-fixtures/config.hcl

+3-1
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,6 @@ disable_sealwrap = true
5151
disable_printable_check = true
5252
enable_response_header_hostname = true
5353
enable_response_header_raft_node_id = true
54-
license_path = "/path/to/license"
54+
license_path = "/path/to/license"
55+
plugin_directory = "/path/to/plugins"
56+
plugin_tmpdir = "/tmp/plugins"

http/sys_config_state_test.go

+1
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ func TestSysConfigState_Sanitized(t *testing.T) {
162162
"max_lease_ttl": json.Number("0"),
163163
"pid_file": "",
164164
"plugin_directory": "",
165+
"plugin_tmpdir": "",
165166
"plugin_file_uid": json.Number("0"),
166167
"plugin_file_permissions": json.Number("0"),
167168
"enable_response_header_hostname": false,

sdk/helper/pluginutil/run_config.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ type runConfig struct {
5656
runtimeConfig *pluginruntimeutil.PluginRuntimeConfig
5757

5858
PluginClientConfig
59+
tmpdir string
5960
}
6061

6162
func (rc runConfig) mlockEnabled() bool {
@@ -144,7 +145,7 @@ func (rc runConfig) makeConfig(ctx context.Context) (*plugin.ClientConfig, error
144145
clientConfig.RunnerFunc = containerCfg.NewContainerRunner
145146
clientConfig.UnixSocketConfig = &plugin.UnixSocketConfig{
146147
Group: strconv.Itoa(containerCfg.GroupAdd),
147-
TempDir: os.Getenv("VAULT_PLUGIN_TMPDIR"),
148+
TempDir: rc.tmpdir,
148149
}
149150
clientConfig.GRPCBrokerMultiplex = true
150151
}
@@ -271,6 +272,7 @@ func (r *PluginRunner) RunConfig(ctx context.Context, opts ...RunOpt) (*plugin.C
271272
sha256: r.Sha256,
272273
env: r.Env,
273274
runtimeConfig: r.RuntimeConfig,
275+
tmpdir: r.Tmpdir,
274276
PluginClientConfig: PluginClientConfig{
275277
Name: r.Name,
276278
PluginType: r.Type,

sdk/helper/pluginutil/runner.go

+1
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ type PluginRunner struct {
6969
Builtin bool `json:"builtin" structs:"builtin"`
7070
BuiltinFactory func() (interface{}, error) `json:"-" structs:"-"`
7171
RuntimeConfig *prutil.PluginRuntimeConfig `json:"-" structs:"-"`
72+
Tmpdir string `json:"-" structs:"-"`
7273
}
7374

7475
// BinaryReference returns either the OCI image reference if it's a container

vault/core.go

+19-1
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,9 @@ type Core struct {
535535

536536
// pluginDirectory is the location vault will look for plugin binaries
537537
pluginDirectory string
538+
// pluginTmpdir is the location vault will use for containerized plugin
539+
// temporary files
540+
pluginTmpdir string
538541

539542
// pluginFileUid is the uid of the plugin files and directory
540543
pluginFileUid int
@@ -822,6 +825,7 @@ type CoreConfig struct {
822825
EnableIntrospection bool
823826

824827
PluginDirectory string
828+
PluginTmpdir string
825829

826830
PluginFileUid int
827831

@@ -1240,6 +1244,12 @@ func NewCore(conf *CoreConfig) (*Core, error) {
12401244
return nil, fmt.Errorf("core setup failed, could not verify plugin directory: %w", err)
12411245
}
12421246
}
1247+
if conf.PluginTmpdir != "" {
1248+
c.pluginTmpdir, err = filepath.Abs(conf.PluginTmpdir)
1249+
if err != nil {
1250+
return nil, fmt.Errorf("core setup failed, could not verify plugin tmpdir: %w", err)
1251+
}
1252+
}
12431253

12441254
if conf.PluginFileUid != 0 {
12451255
c.pluginFileUid = conf.PluginFileUid
@@ -2517,7 +2527,15 @@ func (c *Core) setupPluginRuntimeCatalog(ctx context.Context) error {
25172527
// this method can be included in the slice of functions returned by the
25182528
// buildUnsealSetupFunctionsSlice function.
25192529
func (c *Core) setupPluginCatalog(ctx context.Context) error {
2520-
pluginCatalog, err := plugincatalog.SetupPluginCatalog(ctx, c.logger, c.builtinRegistry, NewBarrierView(c.barrier, pluginCatalogPath), c.pluginDirectory, c.enableMlock, c.pluginRuntimeCatalog)
2530+
pluginCatalog, err := plugincatalog.SetupPluginCatalog(ctx, &plugincatalog.PluginCatalogInput{
2531+
Logger: c.logger,
2532+
BuiltinRegistry: c.builtinRegistry,
2533+
CatalogView: NewBarrierView(c.barrier, pluginCatalogPath),
2534+
PluginDirectory: c.pluginDirectory,
2535+
Tmpdir: c.pluginTmpdir,
2536+
EnableMlock: c.enableMlock,
2537+
PluginRuntimeCatalog: c.pluginRuntimeCatalog,
2538+
})
25212539
if err != nil {
25222540
return err
25232541
}

vault/external_plugin_container_test.go

+31-5
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import (
1717
"github.com/hashicorp/vault/sdk/logical"
1818
)
1919

20-
func testClusterWithContainerPlugins(t *testing.T, types []consts.PluginType) (*Core, []pluginhelpers.TestPlugin) {
20+
func testClusterWithContainerPlugins(t *testing.T, types []consts.PluginType) (*TestClusterCore, []pluginhelpers.TestPlugin) {
2121
var plugins []*TestPluginConfig
2222
for _, typ := range types {
2323
plugins = append(plugins, &TestPluginConfig{
@@ -26,15 +26,28 @@ func testClusterWithContainerPlugins(t *testing.T, types []consts.PluginType) (*
2626
Container: true,
2727
})
2828
}
29-
cluster := NewTestCluster(t, &CoreConfig{}, &TestClusterOptions{
29+
// Use os.MkdirTemp because t.TempDir() exceeds the Unix socket length limit.
30+
// See https://www.man7.org/linux/man-pages/man7/unix.7.html for details.
31+
tmpdir, err := os.MkdirTemp("", "")
32+
if err != nil {
33+
t.Fatal(err)
34+
}
35+
t.Cleanup(func() {
36+
if err := os.RemoveAll(tmpdir); err != nil {
37+
t.Fatal(err)
38+
}
39+
})
40+
cluster := NewTestCluster(t, &CoreConfig{
41+
PluginTmpdir: tmpdir,
42+
}, &TestClusterOptions{
3043
Plugins: plugins,
3144
})
3245

3346
cluster.Start()
3447
t.Cleanup(cluster.Cleanup)
3548

36-
core := cluster.Cores[0].Core
37-
TestWaitActive(t, core)
49+
core := cluster.Cores[0]
50+
TestWaitActive(t, core.Core)
3851

3952
return core, cluster.Plugins
4053
}
@@ -81,14 +94,26 @@ func TestExternalPluginInContainer_MountAndUnmount(t *testing.T) {
8194
})
8295
}
8396

84-
func mountAndUnmountContainerPlugin_WithRuntime(t *testing.T, c *Core, plugin pluginhelpers.TestPlugin, ociRuntime string, rootless bool) {
97+
func mountAndUnmountContainerPlugin_WithRuntime(t *testing.T, c *TestClusterCore, plugin pluginhelpers.TestPlugin, ociRuntime string, rootless bool) {
8598
if ociRuntime != "" {
8699
registerPluginRuntime(t, c.systemBackend, ociRuntime, rootless)
87100
}
88101
registerContainerPlugin(t, c.systemBackend, plugin.Name, plugin.Typ.String(), "1.0.0", plugin.ImageSha256, plugin.Image, ociRuntime)
89102

90103
mountPlugin(t, c.systemBackend, plugin.Name, plugin.Typ, "v1.0.0", "")
91104

105+
expectTmpdirEntries := func(expected int) {
106+
t.Helper()
107+
entries, err := os.ReadDir(c.CoreConfig.PluginTmpdir)
108+
if err != nil {
109+
t.Fatal(err)
110+
}
111+
if len(entries) != expected {
112+
t.Fatalf("expected %d in tmpdir, got %v", expected, entries)
113+
}
114+
}
115+
expectTmpdirEntries(1)
116+
92117
routeRequest := func(expectMatch bool) {
93118
pluginPath := "foo/bar"
94119
if plugin.Typ == consts.PluginTypeCredential {
@@ -106,6 +131,7 @@ func mountAndUnmountContainerPlugin_WithRuntime(t *testing.T, c *Core, plugin pl
106131
routeRequest(true)
107132
unmountPlugin(t, c.systemBackend, plugin.Typ, "foo")
108133
routeRequest(false)
134+
expectTmpdirEntries(0)
109135
}
110136

111137
func registerContainerPlugin(t *testing.T, sys *SystemBackend, pluginName, pluginType, version, sha, image, runtime string) {

vault/plugincatalog/plugin_catalog.go

+39-21
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ type PluginCatalog struct {
4848
builtinRegistry BuiltinRegistry
4949
catalogView logical.Storage
5050
directory string
51+
tmpdir string
5152
logger log.Logger
5253

5354
// externalPlugins holds plugin process connections by a key which is
@@ -138,37 +139,42 @@ type pluginClient struct {
138139
plugin.ClientProtocol
139140
}
140141

141-
func SetupPluginCatalog(
142-
ctx context.Context,
143-
logger log.Logger,
144-
builtinRegistry BuiltinRegistry,
145-
catalogView logical.Storage,
146-
pluginDirectory string,
147-
enableMlock bool,
148-
pluginRuntimeCatalog *PluginRuntimeCatalog,
149-
) (*PluginCatalog, error) {
150-
pluginCatalog := &PluginCatalog{
151-
builtinRegistry: builtinRegistry,
152-
catalogView: catalogView,
153-
directory: pluginDirectory,
142+
type PluginCatalogInput struct {
143+
Logger log.Logger
144+
BuiltinRegistry BuiltinRegistry
145+
CatalogView logical.Storage
146+
PluginDirectory string
147+
Tmpdir string
148+
EnableMlock bool
149+
PluginRuntimeCatalog *PluginRuntimeCatalog
150+
}
151+
152+
func SetupPluginCatalog(ctx context.Context, in *PluginCatalogInput) (*PluginCatalog, error) {
153+
logger := in.Logger
154+
catalog := &PluginCatalog{
155+
builtinRegistry: in.BuiltinRegistry,
156+
catalogView: in.CatalogView,
157+
directory: in.PluginDirectory,
158+
tmpdir: in.Tmpdir,
154159
logger: logger,
155-
mlockPlugins: enableMlock,
160+
mlockPlugins: in.EnableMlock,
156161
wrapper: logical.StaticSystemView{VersionString: version.GetVersion().Version},
157-
runtimeCatalog: pluginRuntimeCatalog,
162+
runtimeCatalog: in.PluginRuntimeCatalog,
158163
}
159164

160165
// Run upgrade if untyped plugins exist
161-
err := pluginCatalog.UpgradePlugins(ctx, logger)
166+
err := catalog.upgradePlugins(ctx, logger)
162167
if err != nil {
163168
logger.Error("error while upgrading plugin storage", "error", err)
164169
return nil, err
165170
}
166171

167-
if logger.IsInfo() {
168-
logger.Info("successfully setup plugin catalog", "plugin-directory", pluginDirectory)
172+
logger.Info("successfully setup plugin catalog", "plugin-directory", catalog.directory)
173+
if catalog.tmpdir != "" {
174+
logger.Debug("plugin temporary directory configured", "tmpdir", catalog.tmpdir)
169175
}
170176

171-
return pluginCatalog, nil
177+
return catalog, nil
172178
}
173179

174180
type pluginClientConn struct {
@@ -723,9 +729,9 @@ func (c *PluginCatalog) isDatabasePlugin(ctx context.Context, pluginRunner *plug
723729
return merr.ErrorOrNil()
724730
}
725731

726-
// UpgradePlugins will loop over all the plugins of unknown type and attempt to
732+
// upgradePlugins will loop over all the plugins of unknown type and attempt to
727733
// upgrade them to typed plugins
728-
func (c *PluginCatalog) UpgradePlugins(ctx context.Context, logger log.Logger) error {
734+
func (c *PluginCatalog) upgradePlugins(ctx context.Context, logger log.Logger) error {
729735
c.lock.Lock()
730736
defer c.lock.Unlock()
731737

@@ -739,6 +745,10 @@ func (c *PluginCatalog) UpgradePlugins(ctx context.Context, logger log.Logger) e
739745
if err != nil {
740746
return err
741747
}
748+
if len(pluginsRaw) == 0 {
749+
return nil
750+
}
751+
742752
plugins := make([]string, 0, len(pluginsRaw))
743753
for _, p := range pluginsRaw {
744754
if !strings.HasSuffix(p, "/") {
@@ -838,6 +848,7 @@ func (c *PluginCatalog) get(ctx context.Context, name string, pluginType consts.
838848
// If none of the cases are satisfied, we'll search for a builtin plugin below.
839849
switch {
840850
case entry.OCIImage != "":
851+
entry.Tmpdir = c.tmpdir
841852
if entry.Runtime != "" {
842853
entry.RuntimeConfig, err = c.runtimeCatalog.Get(ctx, entry.Runtime, consts.PluginRuntimeTypeContainer)
843854
if err != nil {
@@ -1085,6 +1096,9 @@ func (c *PluginCatalog) ListPluginsWithRuntime(ctx context.Context, runtime stri
10851096
if plugin.Runtime == runtime {
10861097
ret = append(ret, plugin.Name)
10871098
}
1099+
if plugin.OCIImage != "" {
1100+
plugin.Tmpdir = c.tmpdir
1101+
}
10881102
}
10891103
return ret, nil
10901104
}
@@ -1145,6 +1159,10 @@ func (c *PluginCatalog) listInternal(ctx context.Context, pluginType consts.Plug
11451159
continue
11461160
}
11471161

1162+
if plugin.OCIImage != "" {
1163+
plugin.Tmpdir = c.tmpdir
1164+
}
1165+
11481166
result = append(result, pluginutil.VersionedPlugin{
11491167
Name: plugin.Name,
11501168
Type: plugin.Type.String(),

vault/plugincatalog/plugin_catalog_test.go

+8-6
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,14 @@ func testPluginCatalog(t *testing.T) *PluginCatalog {
5454
pluginRuntimeCatalog := testPluginRuntimeCatalog(t)
5555
pluginCatalog, err := SetupPluginCatalog(
5656
context.Background(),
57-
logger,
58-
corehelpers.NewMockBuiltinRegistry(),
59-
logical.NewLogicalStorage(storage),
60-
testDir,
61-
false,
62-
pluginRuntimeCatalog,
57+
&PluginCatalogInput{
58+
Logger: logger,
59+
BuiltinRegistry: corehelpers.NewMockBuiltinRegistry(),
60+
CatalogView: logical.NewLogicalStorage(storage),
61+
PluginDirectory: testDir,
62+
EnableMlock: false,
63+
PluginRuntimeCatalog: pluginRuntimeCatalog,
64+
},
6365
)
6466
if err != nil {
6567
t.Fatal(err)

0 commit comments

Comments
 (0)