From 61793751001566f9862de2b36024ee716f85b88f Mon Sep 17 00:00:00 2001 From: Richard Lane <32445861+rjl79@users.noreply.github.com> Date: Thu, 20 Sep 2018 14:21:57 +1000 Subject: [PATCH 01/11] Documentation correction - update list identity whitelist sample request (#5369) Path was incorrectly referencing the roletag-blacklist Updated the sample to match the correct path --- website/source/api/auth/aws/index.html.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/source/api/auth/aws/index.html.md b/website/source/api/auth/aws/index.html.md index e5f6e8c7324e..0634487caf7d 100644 --- a/website/source/api/auth/aws/index.html.md +++ b/website/source/api/auth/aws/index.html.md @@ -1163,7 +1163,7 @@ $ curl \ $ curl \ --header "X-Vault-Token: ..." \ --request LIST \ - http://127.0.0.1:8200/v1/auth/aws/roletag-blacklist + http://127.0.0.1:8200/v1/auth/aws/identity-whitelist ``` ### Sample Response From 2b0c7596d4648a7ea35f23f38f2cba07c1c66c40 Mon Sep 17 00:00:00 2001 From: Laura Gjerman-Uva Date: Thu, 20 Sep 2018 09:19:01 -0700 Subject: [PATCH 02/11] Add -dr-token flag to commands to generate OTP and decode with OTP (required on DR secondary as of 0.11) (#5368) --- website/source/guides/operations/disaster-recovery.html.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/website/source/guides/operations/disaster-recovery.html.md b/website/source/guides/operations/disaster-recovery.html.md index dbd9efbbc236..7a45a0e5d82d 100644 --- a/website/source/guides/operations/disaster-recovery.html.md +++ b/website/source/guides/operations/disaster-recovery.html.md @@ -274,7 +274,7 @@ secondary cluster. The process, outlined below using API calls, is the similar t 1. Generate an one time password (OTP) to use: ```plaintext - $ vault operator generate-root -generate-otp + $ vault operator generate-root -dr-token -generate-otp HenFLWmt0AgrjWJp/RECzQ== ``` @@ -361,7 +361,7 @@ entered by each key holder via **`/sys/replication/dr/secondary/generate-operati **Example:** ```plaintext - $ vault operator generate-root \ + $ vault operator generate-root -dr-token \ -decode="dKNQqNmh3JfJcSZdGlkttQ==" \ -otp="HenFLWmt0AgrjWJp/RECzQ==" @@ -426,7 +426,7 @@ using the OTP generated earlier. (Be sure to enter your OTP in the command.) **Example:** ``` - $ vault operator generate-root \ + $ vault operator generate-root -dr-token \ -otp="vZpZZf5UI1nvB3A5/7Xq9A==" \ -decode="cuplaFGYduDEY6ZVC5IfaA==" From 20c2c978d1b602b0f6ef161ebfdf9ded45f71983 Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Thu, 20 Sep 2018 12:38:05 -0400 Subject: [PATCH 03/11] Makefile updates --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 06ee333200d8..d92421e7f2b0 100644 --- a/Makefile +++ b/Makefile @@ -147,9 +147,9 @@ proto: protoc helper/identity/types.proto --go_out=plugins=grpc:../../.. protoc builtin/logical/database/dbplugin/*.proto --go_out=plugins=grpc:../../.. protoc logical/plugin/pb/*.proto --go_out=plugins=grpc:../../.. - sed -i -e 's/Idp/IDP/' -e 's/Url/URL/' -e 's/Id/ID/' -e 's/IDentity/Identity/' -e 's/EntityId/EntityID/' -e 's/Api/API/' -e 's/Qr/QR/' -e 's/Totp/TOTP/' -e 's/Mfa/MFA/' -e 's/Pingid/PingID/' -e 's/protobuf:"/sentinel:"" protobuf:"/' -e 's/namespaceId/namespaceID/' -e 's/Ttl/TTL/' helper/identity/types.pb.go helper/storagepacker/types.pb.go logical/plugin/pb/backend.pb.go logical/identity.pb.go sed -i '1s;^;// +build !enterprise\n;' physical/types.pb.go sed -i '1s;^;// +build !enterprise\n;' helper/identity/mfa/types.pb.go + sed -i -e 's/Idp/IDP/' -e 's/Url/URL/' -e 's/Id/ID/' -e 's/IDentity/Identity/' -e 's/EntityId/EntityID/' -e 's/Api/API/' -e 's/Qr/QR/' -e 's/Totp/TOTP/' -e 's/Mfa/MFA/' -e 's/Pingid/PingID/' -e 's/protobuf:"/sentinel:"" protobuf:"/' -e 's/namespaceId/namespaceID/' -e 's/Ttl/TTL/' -e 's/BoundCidrs/BoundCIDRs/' helper/identity/types.pb.go helper/storagepacker/types.pb.go logical/plugin/pb/backend.pb.go logical/identity.pb.go fmtcheck: @true From f9d85c3d68d0fa44957c352f650be06d4e5c398a Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Thu, 20 Sep 2018 12:45:49 -0400 Subject: [PATCH 04/11] BoundCidrs -> BoundCIDRs --- logical/plugin/pb/backend.pb.go | 12 ++++++------ logical/plugin/pb/translation.go | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/logical/plugin/pb/backend.pb.go b/logical/plugin/pb/backend.pb.go index 712bc7357c3e..0deb27eeb8e4 100644 --- a/logical/plugin/pb/backend.pb.go +++ b/logical/plugin/pb/backend.pb.go @@ -513,7 +513,7 @@ type Auth struct { GroupAliases []*logical.Alias `sentinel:"" protobuf:"bytes,12,rep,name=group_aliases,json=groupAliases,proto3" json:"group_aliases,omitempty"` // If set, restricts usage of the certificates to client IPs falling within // the range of the specified CIDR(s). - BoundCidrs []string `sentinel:"" protobuf:"bytes,13,rep,name=bound_cidrs,json=boundCidrs,proto3" json:"bound_cidrs,omitempty"` + BoundCIDRs []string `sentinel:"" protobuf:"bytes,13,rep,name=bound_cidrs,json=boundCidrs,proto3" json:"bound_cidrs,omitempty"` // TokenPolicies and IdentityPolicies break down the list in Policies to // help determine where a policy was sourced TokenPolicies []string `sentinel:"" protobuf:"bytes,14,rep,name=token_policies,json=tokenPolicies,proto3" json:"token_policies,omitempty"` @@ -631,9 +631,9 @@ func (m *Auth) GetGroupAliases() []*logical.Alias { return nil } -func (m *Auth) GetBoundCidrs() []string { +func (m *Auth) GetBoundCIDRs() []string { if m != nil { - return m.BoundCidrs + return m.BoundCIDRs } return nil } @@ -667,7 +667,7 @@ type TokenEntry struct { Role string `sentinel:"" protobuf:"bytes,12,opt,name=role,proto3" json:"role,omitempty"` Period int64 `sentinel:"" protobuf:"varint,13,opt,name=period,proto3" json:"period,omitempty"` EntityID string `sentinel:"" protobuf:"bytes,14,opt,name=entity_id,json=entityId,proto3" json:"entity_id,omitempty"` - BoundCidrs []string `sentinel:"" protobuf:"bytes,15,rep,name=bound_cidrs,json=boundCidrs,proto3" json:"bound_cidrs,omitempty"` + BoundCIDRs []string `sentinel:"" protobuf:"bytes,15,rep,name=bound_cidrs,json=boundCidrs,proto3" json:"bound_cidrs,omitempty"` NamespaceID string `sentinel:"" protobuf:"bytes,16,opt,name=namespace_id,json=namespaceID,proto3" json:"namespace_id,omitempty"` CubbyholeID string `sentinel:"" protobuf:"bytes,17,opt,name=cubbyhole_id,json=cubbyholeId,proto3" json:"cubbyhole_id,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` @@ -797,9 +797,9 @@ func (m *TokenEntry) GetEntityID() string { return "" } -func (m *TokenEntry) GetBoundCidrs() []string { +func (m *TokenEntry) GetBoundCIDRs() []string { if m != nil { - return m.BoundCidrs + return m.BoundCIDRs } return nil } diff --git a/logical/plugin/pb/translation.go b/logical/plugin/pb/translation.go index d60cbf1db17f..ed367f8f6a2a 100644 --- a/logical/plugin/pb/translation.go +++ b/logical/plugin/pb/translation.go @@ -499,7 +499,7 @@ func LogicalAuthToProtoAuth(a *logical.Auth) (*Auth, error) { EntityID: a.EntityID, Alias: a.Alias, GroupAliases: a.GroupAliases, - BoundCidrs: boundCIDRs, + BoundCIDRs: boundCIDRs, }, nil } @@ -519,7 +519,7 @@ func ProtoAuthToLogicalAuth(a *Auth) (*logical.Auth, error) { return nil, err } - boundCIDRs, err := parseutil.ParseAddrs(a.BoundCidrs) + boundCIDRs, err := parseutil.ParseAddrs(a.BoundCIDRs) if err != nil { return nil, err } @@ -573,7 +573,7 @@ func LogicalTokenEntryToProtoTokenEntry(t *logical.TokenEntry) *TokenEntry { Role: t.Role, Period: int64(t.Period), EntityID: t.EntityID, - BoundCidrs: boundCIDRs, + BoundCIDRs: boundCIDRs, NamespaceID: t.NamespaceID, CubbyholeID: t.CubbyholeID, } @@ -584,7 +584,7 @@ func ProtoTokenEntryToLogicalTokenEntry(t *TokenEntry) (*logical.TokenEntry, err return nil, nil } - boundCIDRs, err := parseutil.ParseAddrs(t.BoundCidrs) + boundCIDRs, err := parseutil.ParseAddrs(t.BoundCIDRs) if err != nil { return nil, err } From abdf72992404290de2fc3cfc01ce52c92f10baf3 Mon Sep 17 00:00:00 2001 From: Brian Shumate Date: Thu, 20 Sep 2018 13:25:33 -0400 Subject: [PATCH 05/11] Docs: update Tidy API (#5374) - Add a sample response to /auth/token/tidy API docs - Document /auth/approle/tidy/secret-id API docs --- website/source/api/auth/approle/index.html.md | 37 +++++++++++++++++++ website/source/api/auth/token/index.html.md | 17 +++++++++ 2 files changed, 54 insertions(+) diff --git a/website/source/api/auth/approle/index.html.md b/website/source/api/auth/approle/index.html.md index 95c6809ca228..534947ce2023 100644 --- a/website/source/api/auth/approle/index.html.md +++ b/website/source/api/auth/approle/index.html.md @@ -640,3 +640,40 @@ to be able to delegate specific endpoints using Vault's ACL system. | `GET/POST/DELETE` | `/auth/approle/role/:role_name/period` | `200/204` | Refer to `/auth/approle/role/:role_name` endpoint. + +## Tidy Tokens + +Performs some maintenance tasks to clean up invalid entries that may remain +in the token store. Generally, running this is not needed unless upgrade +notes or support personnel suggest it. This may perform a lot of I/O to the +storage method so should be used sparingly. + +| Method | Path | Produces | +| :------- | :------------------------------ | :--------------------- | +| `POST` | `/auth/approle/tidy/secret-id` | `204 (empty body)` | + +### Sample Request + +``` +$ curl \ + --header "X-Vault-Token: ..." \ + --request POST \ + http://127.0.0.1:8200/v1/auth/approle/tidy/secret-id +``` + +### Sample Response + +```json +{ + "request_id": "b20b56e3-4699-5b19-cc6b-e74f7b787bbf", + "lease_id": "", + "renewable": false, + "lease_duration": 0, + "data": null, + "wrap_info": null, + "warnings": [ + "Tidy operation successfully started. Any information from the operation will be printed to Vault's server logs." + ], + "auth": null +} +``` diff --git a/website/source/api/auth/token/index.html.md b/website/source/api/auth/token/index.html.md index 2522c2f05f0d..58010ca8c8bb 100644 --- a/website/source/api/auth/token/index.html.md +++ b/website/source/api/auth/token/index.html.md @@ -736,3 +736,20 @@ $ curl \ --request POST \ http://127.0.0.1:8200/v1/auth/token/tidy ``` + +### Sample Response + +```json +{ + "request_id": "84437c7f-36a1-6c1d-381d-14ec99217e94", + "lease_id": "", + "renewable": false, + "lease_duration": 0, + "data": null, + "wrap_info": null, + "warnings": [ + "Tidy operation successfully started. Any information from the operation will be printed to Vault's server logs." + ], + "auth": null +} +``` From 494b9a039c7b8d2f65657aad5934b0c59e25e447 Mon Sep 17 00:00:00 2001 From: Calvin Leung Huang Date: Thu, 20 Sep 2018 10:50:29 -0700 Subject: [PATCH 06/11] Add ability to provide env vars to plugins (#5359) * Add ability to provide env vars to plugins * Update docs * Update docs with examples * Refactor TestAddTestPlugin, remove TestAddTestPluginTempDir --- builtin/logical/database/backend_test.go | 2 +- .../logical/database/dbplugin/plugin_test.go | 4 +- builtin/plugin/backend_test.go | 2 +- helper/pluginutil/runner.go | 5 + http/plugin_test.go | 2 +- vault/logical_system.go | 11 +- vault/logical_system_integ_test.go | 106 ++++++++++++++++-- vault/logical_system_paths.go | 4 + vault/plugin_catalog.go | 3 +- vault/plugin_catalog_test.go | 7 +- vault/testing.go | 87 +++++--------- .../source/api/system/plugins-catalog.html.md | 11 +- 12 files changed, 165 insertions(+), 79 deletions(-) diff --git a/builtin/logical/database/backend_test.go b/builtin/logical/database/backend_test.go index b7fe89372edf..eadce0772631 100644 --- a/builtin/logical/database/backend_test.go +++ b/builtin/logical/database/backend_test.go @@ -101,7 +101,7 @@ func getCluster(t *testing.T) (*vault.TestCluster, logical.SystemView) { os.Setenv(pluginutil.PluginCACertPEMEnv, cluster.CACertPEMFile) sys := vault.TestDynamicSystemView(cores[0].Core) - vault.TestAddTestPlugin(t, cores[0].Core, "postgresql-database-plugin", "TestBackend_PluginMain") + vault.TestAddTestPlugin(t, cores[0].Core, "postgresql-database-plugin", "TestBackend_PluginMain", []string{}, "") return cluster, sys } diff --git a/builtin/logical/database/dbplugin/plugin_test.go b/builtin/logical/database/dbplugin/plugin_test.go index 0c20aef1ea04..ff04169819b2 100644 --- a/builtin/logical/database/dbplugin/plugin_test.go +++ b/builtin/logical/database/dbplugin/plugin_test.go @@ -94,8 +94,8 @@ func getCluster(t *testing.T) (*vault.TestCluster, logical.SystemView) { cores := cluster.Cores sys := vault.TestDynamicSystemView(cores[0].Core) - vault.TestAddTestPlugin(t, cores[0].Core, "test-plugin", "TestPlugin_GRPC_Main") - vault.TestAddTestPlugin(t, cores[0].Core, "test-plugin-netRPC", "TestPlugin_NetRPC_Main") + vault.TestAddTestPlugin(t, cores[0].Core, "test-plugin", "TestPlugin_GRPC_Main", []string{}, "") + vault.TestAddTestPlugin(t, cores[0].Core, "test-plugin-netRPC", "TestPlugin_NetRPC_Main", []string{}, "") return cluster, sys } diff --git a/builtin/plugin/backend_test.go b/builtin/plugin/backend_test.go index 4667717ae800..f90d9450b65e 100644 --- a/builtin/plugin/backend_test.go +++ b/builtin/plugin/backend_test.go @@ -89,7 +89,7 @@ func testConfig(t *testing.T) (*logical.BackendConfig, func()) { os.Setenv(pluginutil.PluginCACertPEMEnv, cluster.CACertPEMFile) - vault.TestAddTestPlugin(t, core.Core, "mock-plugin", "TestBackend_PluginMain") + vault.TestAddTestPlugin(t, core.Core, "mock-plugin", "TestBackend_PluginMain", []string{}, "") return config, func() { cluster.Cleanup() diff --git a/helper/pluginutil/runner.go b/helper/pluginutil/runner.go index 436e169fe883..41b32d946338 100644 --- a/helper/pluginutil/runner.go +++ b/helper/pluginutil/runner.go @@ -43,6 +43,7 @@ type PluginRunner struct { Name string `json:"name" structs:"name"` Command string `json:"command" structs:"command"` Args []string `json:"args" structs:"args"` + Env []string `json:"env" structs:"env"` Sha256 []byte `json:"sha256" structs:"sha256"` Builtin bool `json:"builtin" structs:"builtin"` BuiltinFactory func() (interface{}, error) `json:"-" structs:"-"` @@ -65,6 +66,10 @@ func (r *PluginRunner) RunMetadataMode(ctx context.Context, wrapper RunnerUtil, func (r *PluginRunner) runCommon(ctx context.Context, wrapper RunnerUtil, pluginMap map[string]plugin.Plugin, hs plugin.HandshakeConfig, env []string, logger log.Logger, isMetadataMode bool) (*plugin.Client, error) { cmd := exec.Command(r.Command, r.Args...) + + // `env` should always go last to avoid overwriting internal values that might + // have been provided externally. + cmd.Env = append(cmd.Env, r.Env...) cmd.Env = append(cmd.Env, env...) // Add the mlock setting to the ENV of the plugin diff --git a/http/plugin_test.go b/http/plugin_test.go index 3fb55dd520bb..bdedc0e699bb 100644 --- a/http/plugin_test.go +++ b/http/plugin_test.go @@ -50,7 +50,7 @@ func getPluginClusterAndCore(t testing.TB, logger log.Logger) (*vault.TestCluste os.Setenv(pluginutil.PluginCACertPEMEnv, cluster.CACertPEMFile) vault.TestWaitActive(t, core.Core) - vault.TestAddTestPlugin(t, core.Core, "mock-plugin", "TestPlugin_PluginMain") + vault.TestAddTestPlugin(t, core.Core, "mock-plugin", "TestPlugin_PluginMain", []string{}, "") // Mount the mock plugin err = core.Client.Sys().Mount("mock", &api.MountInput{ diff --git a/vault/logical_system.go b/vault/logical_system.go index db1cd193fc11..9ef54e194dc0 100644 --- a/vault/logical_system.go +++ b/vault/logical_system.go @@ -269,7 +269,7 @@ func (b *SystemBackend) handlePluginCatalogUpdate(ctx context.Context, req *logi return logical.ErrorResponse("missing command value"), nil } - // For backwards compatibility, also accept args as part of command. Don't + // For backwards compatibility, also accept args as part of command. Don't // accepts args in both command and args. args := d.Get("args").([]string) parts := strings.Split(command, " ") @@ -281,12 +281,14 @@ func (b *SystemBackend) handlePluginCatalogUpdate(ctx context.Context, req *logi args = parts[1:] } + env := d.Get("env").([]string) + sha256Bytes, err := hex.DecodeString(sha256) if err != nil { return logical.ErrorResponse("Could not decode SHA-256 value from Hex"), err } - err = b.Core.pluginCatalog.Set(ctx, pluginName, parts[0], args, sha256Bytes) + err = b.Core.pluginCatalog.Set(ctx, pluginName, parts[0], args, env, sha256Bytes) if err != nil { return nil, err } @@ -3526,6 +3528,11 @@ plugin directory.`, `The args passed to plugin command.`, "", }, + "plugin-catalog_env": { + `The environment variables passed to plugin command. +Each entry is of the form "key=value".`, + "", + }, "leases": { `View or list lease metadata.`, ` diff --git a/vault/logical_system_integ_test.go b/vault/logical_system_integ_test.go index 6f0ae0826164..4b03344c25fe 100644 --- a/vault/logical_system_integ_test.go +++ b/vault/logical_system_integ_test.go @@ -20,6 +20,11 @@ import ( "github.com/hashicorp/vault/vault" ) +const ( + expectedEnvKey = "FOO" + expectedEnvValue = "BAR" +) + func TestSystemBackend_Plugin_secret(t *testing.T) { cluster := testSystemBackendMock(t, 1, 1, logical.TypeLogical) defer cluster.Cleanup() @@ -103,7 +108,7 @@ func TestSystemBackend_Plugin_MismatchType(t *testing.T) { core := cluster.Cores[0] // Replace the plugin with a credential backend - vault.TestAddTestPlugin(t, core.Core, "mock-plugin", "TestBackend_PluginMainCredentials") + vault.TestAddTestPlugin(t, core.Core, "mock-plugin", "TestBackend_PluginMainCredentials", []string{}, "") // Make a request to lazy load the now-credential plugin // and expect an error @@ -178,7 +183,7 @@ func testPlugin_CatalogRemoved(t *testing.T, btype logical.BackendType, testMoun switch btype { case logical.TypeLogical: // Add plugin back to the catalog - vault.TestAddTestPlugin(t, core.Core, "mock-plugin", "TestBackend_PluginMainLogical") + vault.TestAddTestPlugin(t, core.Core, "mock-plugin", "TestBackend_PluginMainLogical", []string{}, "") _, err = core.Client.Logical().Write("sys/mounts/mock-0", map[string]interface{}{ "type": "plugin", "config": map[string]interface{}{ @@ -187,7 +192,7 @@ func testPlugin_CatalogRemoved(t *testing.T, btype logical.BackendType, testMoun }) case logical.TypeCredential: // Add plugin back to the catalog - vault.TestAddTestPlugin(t, core.Core, "mock-plugin", "TestBackend_PluginMainCredentials") + vault.TestAddTestPlugin(t, core.Core, "mock-plugin", "TestBackend_PluginMainCredentials", []string{}, "") _, err = core.Client.Logical().Write("sys/auth/mock-0", map[string]interface{}{ "type": "plugin", "plugin_name": "mock-plugin", @@ -283,9 +288,9 @@ func testPlugin_continueOnError(t *testing.T, btype logical.BackendType, mismatc // Re-add the plugin to the catalog switch btype { case logical.TypeLogical: - vault.TestAddTestPluginTempDir(t, core.Core, "mock-plugin", "TestBackend_PluginMainLogical", cluster.TempDir) + vault.TestAddTestPlugin(t, core.Core, "mock-plugin", "TestBackend_PluginMainLogical", []string{}, cluster.TempDir) case logical.TypeCredential: - vault.TestAddTestPluginTempDir(t, core.Core, "mock-plugin", "TestBackend_PluginMainCredentials", cluster.TempDir) + vault.TestAddTestPlugin(t, core.Core, "mock-plugin", "TestBackend_PluginMainCredentials", []string{}, cluster.TempDir) } // Reload the plugin @@ -480,7 +485,7 @@ func testSystemBackendMock(t *testing.T, numCores, numMounts int, backendType lo switch backendType { case logical.TypeLogical: - vault.TestAddTestPluginTempDir(t, core.Core, "mock-plugin", "TestBackend_PluginMainLogical", tempDir) + vault.TestAddTestPlugin(t, core.Core, "mock-plugin", "TestBackend_PluginMainLogical", []string{}, tempDir) for i := 0; i < numMounts; i++ { // Alternate input styles for plugin_name on every other mount options := map[string]interface{}{ @@ -502,7 +507,7 @@ func testSystemBackendMock(t *testing.T, numCores, numMounts int, backendType lo } } case logical.TypeCredential: - vault.TestAddTestPluginTempDir(t, core.Core, "mock-plugin", "TestBackend_PluginMainCredentials", tempDir) + vault.TestAddTestPlugin(t, core.Core, "mock-plugin", "TestBackend_PluginMainCredentials", []string{}, tempDir) for i := 0; i < numMounts; i++ { // Alternate input styles for plugin_name on every other mount options := map[string]interface{}{ @@ -530,6 +535,58 @@ func testSystemBackendMock(t *testing.T, numCores, numMounts int, backendType lo return cluster } +func TestSystemBackend_Plugin_Env(t *testing.T) { + kvPair := fmt.Sprintf("%s=%s", expectedEnvKey, expectedEnvValue) + cluster := testSystemBackend_SingleCluster_Env(t, []string{kvPair}) + defer cluster.Cleanup() +} + +// testSystemBackend_SingleCluster_Env is a helper func that returns a single +// cluster and a single mounted plugin logical backend. +func testSystemBackend_SingleCluster_Env(t *testing.T, env []string) *vault.TestCluster { + coreConfig := &vault.CoreConfig{ + LogicalBackends: map[string]logical.Factory{ + "plugin": plugin.Factory, + }, + } + + // Create a tempdir, cluster.Cleanup will clean up this directory + tempDir, err := ioutil.TempDir("", "vault-test-cluster") + if err != nil { + t.Fatal(err) + } + + cluster := vault.NewTestCluster(t, coreConfig, &vault.TestClusterOptions{ + HandlerFunc: vaulthttp.Handler, + KeepStandbysSealed: true, + NumCores: 1, + TempDir: tempDir, + }) + cluster.Start() + + core := cluster.Cores[0] + vault.TestWaitActive(t, core.Core) + client := core.Client + + os.Setenv(pluginutil.PluginCACertPEMEnv, cluster.CACertPEMFile) + + vault.TestAddTestPlugin(t, core.Core, "mock-plugin", "TestBackend_PluginMainEnv", env, tempDir) + options := map[string]interface{}{ + "type": "plugin", + "plugin_name": "mock-plugin", + } + + resp, err := client.Logical().Write("sys/mounts/mock", options) + if err != nil { + t.Fatalf("err: %v", err) + } + if resp != nil { + t.Fatalf("bad: %v", resp) + } + + return cluster +} + func TestBackend_PluginMainLogical(t *testing.T) { args := []string{} if os.Getenv(pluginutil.PluginUnwrapTokenEnv) == "" && os.Getenv(pluginutil.PluginMetadataModeEnv) != "true" { @@ -588,6 +645,41 @@ func TestBackend_PluginMainCredentials(t *testing.T) { } } +// TestBackend_PluginMainEnv is a mock plugin that simply checks for the existence of FOO env var. +func TestBackend_PluginMainEnv(t *testing.T) { + actual := os.Getenv(expectedEnvKey) + if actual != expectedEnvValue { + t.Fatalf("expected: %q, got: %q", expectedEnvValue, actual) + } + + args := []string{} + if os.Getenv(pluginutil.PluginUnwrapTokenEnv) == "" && os.Getenv(pluginutil.PluginMetadataModeEnv) != "true" { + return + } + + caPEM := os.Getenv(pluginutil.PluginCACertPEMEnv) + if caPEM == "" { + t.Fatal("CA cert not passed in") + } + args = append(args, fmt.Sprintf("--ca-cert=%s", caPEM)) + + apiClientMeta := &pluginutil.APIClientMeta{} + flags := apiClientMeta.FlagSet() + flags.Parse(args) + tlsConfig := apiClientMeta.GetTLSConfig() + tlsProviderFunc := pluginutil.VaultPluginTLSProvider(tlsConfig) + + factoryFunc := mock.FactoryType(logical.TypeLogical) + + err := lplugin.Serve(&lplugin.ServeOpts{ + BackendFactoryFunc: factoryFunc, + TLSProviderFunc: tlsProviderFunc, + }) + if err != nil { + t.Fatal(err) + } +} + func TestSystemBackend_InternalUIResultantACL(t *testing.T) { cluster := vault.NewTestCluster(t, nil, &vault.TestClusterOptions{ HandlerFunc: vaulthttp.Handler, diff --git a/vault/logical_system_paths.go b/vault/logical_system_paths.go index 1a33c5618f57..3f9c2f0d86f3 100644 --- a/vault/logical_system_paths.go +++ b/vault/logical_system_paths.go @@ -293,6 +293,10 @@ func (b *SystemBackend) pluginsCatalogPath() *framework.Path { Type: framework.TypeStringSlice, Description: strings.TrimSpace(sysHelp["plugin-catalog_args"][0]), }, + "env": &framework.FieldSchema{ + Type: framework.TypeStringSlice, + Description: strings.TrimSpace(sysHelp["plugin-catalog_env"][0]), + }, }, Callbacks: map[logical.Operation]framework.OperationFunc{ diff --git a/vault/plugin_catalog.go b/vault/plugin_catalog.go index 633b7c341def..f7a25619fe32 100644 --- a/vault/plugin_catalog.go +++ b/vault/plugin_catalog.go @@ -87,7 +87,7 @@ func (c *PluginCatalog) Get(ctx context.Context, name string) (*pluginutil.Plugi // Set registers a new external plugin with the catalog, or updates an existing // external plugin. It takes the name, command and SHA256 of the plugin. -func (c *PluginCatalog) Set(ctx context.Context, name, command string, args []string, sha256 []byte) error { +func (c *PluginCatalog) Set(ctx context.Context, name, command string, args []string, env []string, sha256 []byte) error { if c.directory == "" { return ErrDirectoryNotConfigured } @@ -122,6 +122,7 @@ func (c *PluginCatalog) Set(ctx context.Context, name, command string, args []st Name: name, Command: command, Args: args, + Env: env, Sha256: sha256, Builtin: false, } diff --git a/vault/plugin_catalog_test.go b/vault/plugin_catalog_test.go index a99cac8c97ea..7222959cc954 100644 --- a/vault/plugin_catalog_test.go +++ b/vault/plugin_catalog_test.go @@ -52,7 +52,7 @@ func TestPluginCatalog_CRUD(t *testing.T) { defer file.Close() command := fmt.Sprintf("%s", filepath.Base(file.Name())) - err = core.pluginCatalog.Set(context.Background(), "mysql-database-plugin", command, []string{"--test"}, []byte{'1'}) + err = core.pluginCatalog.Set(context.Background(), "mysql-database-plugin", command, []string{"--test"}, []string{"FOO=BAR"}, []byte{'1'}) if err != nil { t.Fatal(err) } @@ -67,6 +67,7 @@ func TestPluginCatalog_CRUD(t *testing.T) { Name: "mysql-database-plugin", Command: filepath.Join(sym, filepath.Base(file.Name())), Args: []string{"--test"}, + Env: []string{"FOO=BAR"}, Sha256: []byte{'1'}, Builtin: false, } @@ -141,13 +142,13 @@ func TestPluginCatalog_List(t *testing.T) { defer file.Close() command := filepath.Base(file.Name()) - err = core.pluginCatalog.Set(context.Background(), "mysql-database-plugin", command, []string{"--test"}, []byte{'1'}) + err = core.pluginCatalog.Set(context.Background(), "mysql-database-plugin", command, []string{"--test"}, []string{}, []byte{'1'}) if err != nil { t.Fatal(err) } // Set another plugin - err = core.pluginCatalog.Set(context.Background(), "aaaaaaa", command, []string{"--test"}, []byte{'1'}) + err = core.pluginCatalog.Set(context.Background(), "aaaaaaa", command, []string{"--test"}, []string{}, []byte{'1'}) if err != nil { t.Fatal(err) } diff --git a/vault/testing.go b/vault/testing.go index 32c997ae79dc..8341c83fcbc2 100644 --- a/vault/testing.go +++ b/vault/testing.go @@ -347,79 +347,49 @@ func TestDynamicSystemView(c *Core) *dynamicSystemView { } // TestAddTestPlugin registers the testFunc as part of the plugin command to the -// plugin catalog. -func TestAddTestPlugin(t testing.T, c *Core, name, testFunc string) { +// plugin catalog. If provided, uses tmpDir as the plugin directory. +func TestAddTestPlugin(t testing.T, c *Core, name, testFunc string, env []string, tempDir string) { file, err := os.Open(os.Args[0]) if err != nil { t.Fatal(err) } defer file.Close() - hash := sha256.New() - - _, err = io.Copy(hash, file) - if err != nil { - t.Fatal(err) - } - - sum := hash.Sum(nil) - - // Determine plugin directory path - fullPath, err := filepath.EvalSymlinks(os.Args[0]) - if err != nil { - t.Fatal(err) - } - directoryPath := filepath.Dir(fullPath) + dirPath := filepath.Dir(os.Args[0]) + fileName := filepath.Base(os.Args[0]) - // Set core's plugin directory and plugin catalog directory - c.pluginDirectory = directoryPath - c.pluginCatalog.directory = directoryPath - - command := fmt.Sprintf("%s", filepath.Base(os.Args[0])) - args := []string{fmt.Sprintf("--test.run=%s", testFunc)} - err = c.pluginCatalog.Set(context.Background(), name, command, args, sum) - if err != nil { - t.Fatal(err) - } -} - -// TestAddTestPluginTempDir registers the testFunc as part of the plugin command to the -// plugin catalog. It uses tmpDir as the plugin directory. -func TestAddTestPluginTempDir(t testing.T, c *Core, name, testFunc, tempDir string) { - file, err := os.Open(os.Args[0]) - if err != nil { - t.Fatal(err) - } - defer file.Close() + if tempDir != "" { + fi, err := file.Stat() + if err != nil { + t.Fatal(err) + } - fi, err := file.Stat() - if err != nil { - t.Fatal(err) - } + // Copy over the file to the temp dir + dst := filepath.Join(tempDir, fileName) + out, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, fi.Mode()) + if err != nil { + t.Fatal(err) + } + defer out.Close() - // Copy over the file to the temp dir - dst := filepath.Join(tempDir, filepath.Base(os.Args[0])) - out, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, fi.Mode()) - if err != nil { - t.Fatal(err) - } - defer out.Close() + if _, err = io.Copy(out, file); err != nil { + t.Fatal(err) + } + err = out.Sync() + if err != nil { + t.Fatal(err) + } - if _, err = io.Copy(out, file); err != nil { - t.Fatal(err) - } - err = out.Sync() - if err != nil { - t.Fatal(err) + dirPath = tempDir } - // Determine plugin directory full path - fullPath, err := filepath.EvalSymlinks(tempDir) + // Determine plugin directory full path, evaluating potential symlink path + fullPath, err := filepath.EvalSymlinks(dirPath) if err != nil { t.Fatal(err) } - reader, err := os.Open(filepath.Join(fullPath, filepath.Base(os.Args[0]))) + reader, err := os.Open(filepath.Join(fullPath, fileName)) if err != nil { t.Fatal(err) } @@ -439,9 +409,8 @@ func TestAddTestPluginTempDir(t testing.T, c *Core, name, testFunc, tempDir stri c.pluginDirectory = fullPath c.pluginCatalog.directory = fullPath - command := fmt.Sprintf("%s", filepath.Base(os.Args[0])) args := []string{fmt.Sprintf("--test.run=%s", testFunc)} - err = c.pluginCatalog.Set(context.Background(), name, command, args, sum) + err = c.pluginCatalog.Set(context.Background(), name, fileName, args, env, sum) if err != nil { t.Fatal(err) } diff --git a/website/source/api/system/plugins-catalog.html.md b/website/source/api/system/plugins-catalog.html.md index ee66673aee4e..6f24ec5e6981 100644 --- a/website/source/api/system/plugins-catalog.html.md +++ b/website/source/api/system/plugins-catalog.html.md @@ -67,8 +67,15 @@ supplied name. they do not match the plugin can not be run. - `command` `(string: )` – Specifies the command used to execute the - plugin. This is relative to the plugin directory. e.g. `"myplugin - --my_flag=1"` + plugin. This is relative to the plugin directory. e.g. `"myplugin"`. + +- `args` `(array: [])` – Specifies the arguments used to execute the plugin. If + the arguments are provided here, the `command` parameter should only contain + the named program. e.g. `"--my_flag=1"`. + +- `env` `(array: [])` – Specifies the environment variables used during the + execution of the plugin. Each entry is of the form "key=value". e.g + `"FOO=BAR"`. ### Sample Payload From a19a5b6d60e783238768fa0375e647c4066e0c20 Mon Sep 17 00:00:00 2001 From: Calvin Leung Huang Date: Thu, 20 Sep 2018 12:32:07 -0700 Subject: [PATCH 07/11] changelog++ --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 44c584ec5fcb..6e48d50f0c6e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,11 @@ BUG FIXES: * core: Re-add deprecated capabilities information for now [GH-5360] * storage/mysql: Fix locking on MariaDB [GH-5343] +IMPROVEMENTS: + + * plugins: Add `env` parameter when registering plugins to the catalog to allow + operators to include environment variables during plugin execution. [GH-5359] + ## 0.11.1.1 (September 17th, 2018) (Enterprise Only) BUG FIXES: From 22269320dea7fb883c6b0af0dd2d6fbd8fc84bf5 Mon Sep 17 00:00:00 2001 From: Yoko Date: Thu, 20 Sep 2018 13:58:29 -0700 Subject: [PATCH 08/11] [Guide] Tokens & Leases guide **Correction** (#5375) * Added Azure Key Vault * Corrected the info about orphan token creation --- website/source/guides/identity/lease.html.md | 61 ++++++++++++------- .../operations/autounseal-aws-kms.html.md | 13 ++-- 2 files changed, 47 insertions(+), 27 deletions(-) diff --git a/website/source/guides/identity/lease.html.md b/website/source/guides/identity/lease.html.md index aa0d8f489c76..e0fd4fd19d94 100644 --- a/website/source/guides/identity/lease.html.md +++ b/website/source/guides/identity/lease.html.md @@ -467,7 +467,7 @@ the attempt to read the secret from the cubbyhole failed. Set the `num_uses` property in the request payload. -```shell +```plaintext $ curl --header "X-Vault-Token: ..." --request POST \ --data '{ "policies": ["default"], "num_uses":2 }' \ http://127.0.0.1:8200/v1/auth/token/create | jq @@ -590,17 +590,20 @@ token renewal period. This value can be an integer value in seconds (e.g. **Example:** ```shell -$ curl --header "X-Vault-Token: ..." --request POST \ - --data @payload.json \ - http://127.0.0.1:8200/v1/auth/token/roles/zabbix - -$ cat payload.json +# API request payload +$ tee payload.json <Step 5: Orphan tokens -**Root** or **sudo users** have the ability to generate **orphan** tokens. Orphan tokens -are **not** children of their parent; therefore, orphan tokens do not expire when their -parent does. - +Orphan tokens are **not** children of their parent; therefore, orphan tokens do +not expire when their parent does. **NOTE:** Orphan tokens still expire when their own max TTL is reached. #### CLI command +The following CLI command requires **root** token or **sudo** capability on the +`auth/token/create` path. + ```shell $ vault token create -orphan ``` #### API call using cURL +To create an orphan token, use the **`auth/token/create-orphan`** endpoint: + ```shell $ curl --header "X-Vault-Token:..." --request POST \ - --data '{ "no_parent": true }' \ http://127.0.0.1:8200/v1/auth/token/create-orphan | jq ``` +Also, you can create an orphan token using the **`auth/token/create`** endpoint with +`no-parent` parameter set to true. + +```shell +$ curl --header "X-Vault-Token:..." --request POST \ + --data '{ "no_parent": true }' \ + http://127.0.0.1:8200/v1/auth/token/create | jq +``` + +!> **NOTE:** The **`auth/token/create`** endpoint requires **root** token or +**sudo** capability to create an orphan token while +**`auth/token/create-orphan`** endpoint does not. ### Step 6: Revoke tokens and leases @@ -747,10 +767,9 @@ $ curl --header "X-Vault-Token:..." --request POST \ http://127.0.0.1:8200/v1/sys/leases/revoke-prefix/auth/token/create # Revoke all tokens by accessor -$ curl \ - --header "X-Vault-Token: ..." --request POST \ - --data '{ "accessor": "2b2b5b83-7f22-fecd-03f0-4e25bf64da11" }' \ - http://127.0.0.1:8200/v1/auth/token/revoke-accessor +$ curl --header "X-Vault-Token: ..." --request POST \ + --data '{ "accessor": "2b2b5b83-7f22-fecd-03f0-4e25bf64da11" }' \ + http://127.0.0.1:8200/v1/auth/token/revoke-accessor ``` diff --git a/website/source/guides/operations/autounseal-aws-kms.html.md b/website/source/guides/operations/autounseal-aws-kms.html.md index 70e6c004ea83..316015d4fbe6 100644 --- a/website/source/guides/operations/autounseal-aws-kms.html.md +++ b/website/source/guides/operations/autounseal-aws-kms.html.md @@ -50,10 +50,11 @@ many different key holders with many different keys. ## Solution -Vault Enterprise supports opt-in automatic unsealing via cloud technologies such -Amazon KMS or Google Cloud KMS. This feature enables operators to delegate the -unsealing process to trusted cloud providers to ease operations in the event of -partial failure and to aid in the creation of new or ephemeral clusters. +Vault Enterprise supports opt-in automatic unsealing via cloud technologies: +Amazon KMS, Azure Key Vault or GCP Cloud KMS. This feature enables operators to +delegate the unsealing process to trusted cloud providers to ease operations in +the event of partial failure and to aid in the creation of new or ephemeral +clusters. ![Unseal with AWS KMS](/assets/images/vault-autounseal-2.png) @@ -61,7 +62,7 @@ partial failure and to aid in the creation of new or ephemeral clusters. This guide assumes the following: -- Access to **Vault Enterprise 0.9.0 or later** which supports AWS KMS as an unseal mechanism +- Access to **Vault Enterprise 0.9.0 or later** - A URL to download Vault Enterprise from (an Amazon S3 bucket will suffice) - AWS account for provisioning cloud resources - [Terraform installed](https://www.terraform.io/intro/getting-started/install.html) @@ -124,7 +125,7 @@ $ export AWS_SECRET_ACCESS_KEY = "" ``` Create a file named **`terraform.tfvars`** and specify your Vault Enterprise -binary download URL. +binary download URL. **Example:** From 99ee1c8208b084e93ab5aa87c91adfccf34bf692 Mon Sep 17 00:00:00 2001 From: Jim Kalafut Date: Thu, 20 Sep 2018 14:56:38 -0700 Subject: [PATCH 09/11] Detect and bypass cycles during token revocation (#5364) Fixes #4803 --- vault/token_store.go | 31 ++++++++++++++++++------- vault/token_store_test.go | 49 +++++++++++++++++++++++++++++++++++---- 2 files changed, 67 insertions(+), 13 deletions(-) diff --git a/vault/token_store.go b/vault/token_store.go index 14d0c601e22c..26dfbd4428c8 100644 --- a/vault/token_store.go +++ b/vault/token_store.go @@ -1404,8 +1404,8 @@ func (ts *TokenStore) revokeTree(ctx context.Context, le *leaseEntry) error { // Updated to be non-recursive and revoke child tokens // before parent tokens(DFS). func (ts *TokenStore) revokeTreeInternal(ctx context.Context, id string) error { - var dfs []string - dfs = append(dfs, id) + dfs := []string{id} + seenIDs := make(map[string]struct{}) var ns *namespace.Namespace @@ -1429,7 +1429,8 @@ func (ts *TokenStore) revokeTreeInternal(ctx context.Context, id string) error { } for l := len(dfs); l > 0; l = len(dfs) { - id := dfs[0] + id := dfs[len(dfs)-1] + seenIDs[id] = struct{}{} saltedCtx := ctx saltedNS := ns @@ -1444,11 +1445,26 @@ func (ts *TokenStore) revokeTreeInternal(ctx context.Context, id string) error { } path := saltedID + "/" - children, err := ts.parentView(saltedNS).List(saltedCtx, path) + childrenRaw, err := ts.parentView(saltedNS).List(saltedCtx, path) if err != nil { return errwrap.Wrapf("failed to scan for children: {{err}}", err) } + // Filter the child list to remove any items that have ever been in the dfs stack. + // This is a robustness check, as a parent/child cycle can lead to an OOM crash. + children := make([]string, 0, len(childrenRaw)) + for _, child := range childrenRaw { + if _, seen := seenIDs[child]; !seen { + children = append(children, child) + } else { + if err = ts.parentView(saltedNS).Delete(saltedCtx, path+child); err != nil { + return errwrap.Wrapf("failed to delete entry: {{err}}", err) + } + + ts.Logger().Warn("token cycle found", "token", child) + } + } + // If the length of the children array is zero, // then we are at a leaf node. if len(children) == 0 { @@ -1464,11 +1480,10 @@ func (ts *TokenStore) revokeTreeInternal(ctx context.Context, id string) error { if l == 1 { return nil } - dfs = dfs[1:] + dfs = dfs[:len(dfs)-1] } else { - // If we make it here, there are children and they must - // be prepended. - dfs = append(children, dfs...) + // If we make it here, there are children and they must be appended. + dfs = append(dfs, children...) } } diff --git a/vault/token_store_test.go b/vault/token_store_test.go index 49a7c7150bde..26de3a0051b7 100644 --- a/vault/token_store_test.go +++ b/vault/token_store_test.go @@ -1004,17 +1004,46 @@ func TestTokenStore_Revoke_Orphan(t *testing.T) { // This was the original function name, and now it just calls // the non recursive version for a variety of depths. func TestTokenStore_RevokeTree(t *testing.T) { - testTokenStore_RevokeTree_NonRecursive(t, 1) - testTokenStore_RevokeTree_NonRecursive(t, 2) - testTokenStore_RevokeTree_NonRecursive(t, 10) + testTokenStore_RevokeTree_NonRecursive(t, 1, false) + testTokenStore_RevokeTree_NonRecursive(t, 2, false) + testTokenStore_RevokeTree_NonRecursive(t, 10, false) + + // corrupted trees with cycles + testTokenStore_RevokeTree_NonRecursive(t, 1, true) + testTokenStore_RevokeTree_NonRecursive(t, 10, true) } // Revokes a given Token Store tree non recursively. // The second parameter refers to the depth of the tree. -func testTokenStore_RevokeTree_NonRecursive(t testing.TB, depth uint64) { +func testTokenStore_RevokeTree_NonRecursive(t testing.TB, depth uint64, injectCycles bool) { c, _, _ := TestCoreUnsealed(t) ts := c.tokenStore root, children := buildTokenTree(t, ts, depth) + + var cyclePaths []string + if injectCycles { + // Make the root the parent of itself + saltedRoot, _ := ts.SaltID(namespace.TestContext(), root.ID) + key := fmt.Sprintf("%s/%s", saltedRoot, saltedRoot) + cyclePaths = append(cyclePaths, key) + le := &logical.StorageEntry{Key: key} + + if err := ts.parentView(namespace.TestNamespace()).Put(namespace.TestContext(), le); err != nil { + t.Fatalf("err: %v", err) + } + + // Make a deep child the parent of a shallow child + shallow, _ := ts.SaltID(namespace.TestContext(), children[0].ID) + deep, _ := ts.SaltID(namespace.TestContext(), children[len(children)-1].ID) + key = fmt.Sprintf("%s/%s", deep, shallow) + cyclePaths = append(cyclePaths, key) + le = &logical.StorageEntry{Key: key} + + if err := ts.parentView(namespace.TestNamespace()).Put(namespace.TestContext(), le); err != nil { + t.Fatalf("err: %v", err) + } + } + err := ts.revokeTree(namespace.TestContext(), &leaseEntry{}) if err.Error() != "cannot tree-revoke blank token" { t.Fatal(err) @@ -1049,6 +1078,16 @@ func testTokenStore_RevokeTree_NonRecursive(t testing.TB, depth uint64) { t.Fatalf("bad: %#v", out) } } + + for _, path := range cyclePaths { + entry, err := ts.parentView(namespace.TestNamespace()).Get(namespace.TestContext(), path) + if err != nil { + t.Fatalf("err: %v", err) + } + if entry != nil { + t.Fatalf("expected reference to be deleted: %v", entry) + } + } } // A benchmark function that tests testTokenStore_RevokeTree_NonRecursive @@ -1058,7 +1097,7 @@ func BenchmarkTokenStore_RevokeTree(b *testing.B) { for _, depth := range benchmarks { b.Run(fmt.Sprintf("Tree of Depth %d", depth), func(b *testing.B) { for i := 0; i < b.N; i++ { - testTokenStore_RevokeTree_NonRecursive(b, depth) + testTokenStore_RevokeTree_NonRecursive(b, depth, false) } }) } From fb78c23476233542b4b0fec2bb16d924561b61d3 Mon Sep 17 00:00:00 2001 From: Jim Kalafut Date: Thu, 20 Sep 2018 15:00:25 -0700 Subject: [PATCH 10/11] changelog++ --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e48d50f0c6e..2cadd1b77613 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ BUG FIXES: * core: Re-add deprecated capabilities information for now [GH-5360] + * core: Fix handling of cyclic token relationships [GH-4803] * storage/mysql: Fix locking on MariaDB [GH-5343] IMPROVEMENTS: From 717165babded9660d43c8ea7d929d895dfd7f289 Mon Sep 17 00:00:00 2001 From: Roman Iuvshyn Date: Fri, 21 Sep 2018 01:55:20 +0300 Subject: [PATCH 11/11] fixes file path option in samples (#5377) fixes file path option in samples --- website/source/api/system/audit.html.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/source/api/system/audit.html.md b/website/source/api/system/audit.html.md index 35a94fd43da9..15e998e653ff 100644 --- a/website/source/api/system/audit.html.md +++ b/website/source/api/system/audit.html.md @@ -40,7 +40,7 @@ $ curl \ "type": "file", "description": "Store logs in a file", "options": { - "path": "/var/log/vault.log" + "file_path": "/var/log/vault.log" } } } @@ -83,7 +83,7 @@ relevant functionality is only supported in Vault Enterprise: { "type": "file", "options": { - "path": "/var/log/vault/log" + "file_path": "/var/log/vault/log" } } ```