mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-11-02 03:27:54 +00:00
Combined Database backend: Add Static Account support to MongoDB (#7003)
* Implement SetCredentials for MongoDB, adding support for static accounts * rework SetCredentials to split from CreateUser, and to parse the url for database * Add integration test for mongodb static account rotation * check the length of the password results to avoid out-of-bounds * remove unused method * use the pre-existing test helper for this. Add parse method to helper * remove unused command
This commit is contained in:
@@ -10,6 +10,7 @@ import (
|
||||
"database/sql"
|
||||
|
||||
"github.com/hashicorp/vault/helper/namespace"
|
||||
"github.com/hashicorp/vault/helper/testhelpers/mongodb"
|
||||
"github.com/hashicorp/vault/sdk/framework"
|
||||
"github.com/hashicorp/vault/sdk/helper/dbtxn"
|
||||
"github.com/hashicorp/vault/sdk/logical"
|
||||
@@ -19,6 +20,8 @@ import (
|
||||
|
||||
const dbUser = "vaultstatictest"
|
||||
|
||||
const testMongoDBRole = `{ "db": "admin", "roles": [ { "role": "readWrite" } ] }`
|
||||
|
||||
func TestBackend_StaticRole_Rotate_basic(t *testing.T) {
|
||||
cluster, sys := getCluster(t)
|
||||
defer cluster.Cleanup()
|
||||
@@ -814,6 +817,142 @@ func TestBackend_StaticRole_Rotations_PostgreSQL(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestBackend_StaticRole_Rotations_MongoDB(t *testing.T) {
|
||||
cluster, sys := getCluster(t)
|
||||
defer cluster.Cleanup()
|
||||
|
||||
config := logical.TestBackendConfig()
|
||||
config.StorageView = &logical.InmemStorage{}
|
||||
config.System = sys
|
||||
|
||||
b, err := Factory(context.Background(), config)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer b.Cleanup(context.Background())
|
||||
|
||||
// allow initQueue to finish
|
||||
bd := b.(*databaseBackend)
|
||||
if bd.credRotationQueue == nil {
|
||||
t.Fatal("database backend had no credential rotation queue")
|
||||
}
|
||||
|
||||
// configure backend, add item and confirm length
|
||||
cleanup, connURL := mongodb.PrepareTestContainerWithDatabase(t, "latest", "vaulttestdb")
|
||||
defer cleanup()
|
||||
|
||||
// Configure a connection
|
||||
data := map[string]interface{}{
|
||||
"connection_url": connURL,
|
||||
"plugin_name": "mongodb-database-plugin",
|
||||
"verify_connection": false,
|
||||
"allowed_roles": []string{"*"},
|
||||
"name": "plugin-mongo-test",
|
||||
}
|
||||
|
||||
req := &logical.Request{
|
||||
Operation: logical.UpdateOperation,
|
||||
Path: "config/plugin-mongo-test",
|
||||
Storage: config.StorageView,
|
||||
Data: data,
|
||||
}
|
||||
resp, err := b.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%s resp:%#v\n", err, resp)
|
||||
}
|
||||
|
||||
// create three static roles with different rotation periods
|
||||
testCases := []string{"65", "130", "5400"}
|
||||
for _, tc := range testCases {
|
||||
roleName := "plugin-static-role-" + tc
|
||||
data = map[string]interface{}{
|
||||
"name": roleName,
|
||||
"db_name": "plugin-mongo-test",
|
||||
"username": "statictestMongo" + tc,
|
||||
"rotation_period": tc,
|
||||
}
|
||||
|
||||
req = &logical.Request{
|
||||
Operation: logical.CreateOperation,
|
||||
Path: "static-roles/" + roleName,
|
||||
Storage: config.StorageView,
|
||||
Data: data,
|
||||
}
|
||||
|
||||
resp, err = b.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%s resp:%#v\n", err, resp)
|
||||
}
|
||||
}
|
||||
|
||||
// verify the queue has 3 items in it
|
||||
if bd.credRotationQueue.Len() != 3 {
|
||||
t.Fatalf("expected 3 items in the rotation queue, got: (%d)", bd.credRotationQueue.Len())
|
||||
}
|
||||
|
||||
// List the roles
|
||||
data = map[string]interface{}{}
|
||||
req = &logical.Request{
|
||||
Operation: logical.ListOperation,
|
||||
Path: "static-roles/",
|
||||
Storage: config.StorageView,
|
||||
Data: data,
|
||||
}
|
||||
resp, err = b.HandleRequest(namespace.RootContext(nil), req)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%s resp:%#v\n", err, resp)
|
||||
}
|
||||
|
||||
keys := resp.Data["keys"].([]string)
|
||||
if len(keys) != 3 {
|
||||
t.Fatalf("expected 3 roles, got: (%d)", len(keys))
|
||||
}
|
||||
|
||||
// capture initial passwords, before the periodic function is triggered
|
||||
pws := make(map[string][]string, 0)
|
||||
pws = capturePasswords(t, b, config, testCases, pws)
|
||||
|
||||
// sleep to make sure the 65s role will be up for rotation by the time the
|
||||
// periodic function ticks
|
||||
time.Sleep(7 * time.Second)
|
||||
|
||||
// sleep 75 to make sure the periodic func has time to actually run
|
||||
time.Sleep(75 * time.Second)
|
||||
pws = capturePasswords(t, b, config, testCases, pws)
|
||||
|
||||
// sleep more, this should allow both sr65 and sr130 to rotate
|
||||
time.Sleep(140 * time.Second)
|
||||
pws = capturePasswords(t, b, config, testCases, pws)
|
||||
|
||||
// verify all pws are as they should
|
||||
pass := true
|
||||
for k, v := range pws {
|
||||
if len(v) < 3 {
|
||||
t.Fatalf("expected to find 3 passwords for (%s), only found (%d)", k, len(v))
|
||||
}
|
||||
switch {
|
||||
case k == "plugin-static-role-65":
|
||||
// expect all passwords to be different
|
||||
if v[0] == v[1] || v[1] == v[2] || v[0] == v[2] {
|
||||
pass = false
|
||||
}
|
||||
case k == "plugin-static-role-130":
|
||||
// expect the first two to be equal, but different from the third
|
||||
if v[0] != v[1] || v[0] == v[2] {
|
||||
pass = false
|
||||
}
|
||||
case k == "plugin-static-role-5400":
|
||||
// expect all passwords to be equal
|
||||
if v[0] != v[1] || v[1] != v[2] {
|
||||
pass = false
|
||||
}
|
||||
}
|
||||
}
|
||||
if !pass {
|
||||
t.Fatalf("password rotations did not match expected: %#v", pws)
|
||||
}
|
||||
}
|
||||
|
||||
// capturePasswords captures the current passwords at the time of calling, and
|
||||
// returns a map of username / passwords building off of the input map
|
||||
func capturePasswords(t *testing.T, b logical.Backend, config *logical.BackendConfig, testCases []string, pws map[string][]string) map[string][]string {
|
||||
|
||||
Reference in New Issue
Block a user