From e585bfcd40d4a34435e8cd8ca5631e24d4cbb500 Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Wed, 11 Mar 2015 15:19:41 -0700 Subject: [PATCH] vault: Loading mount tables on start --- vault/core.go | 22 +++++++++++ vault/core_test.go | 2 +- vault/mount.go | 97 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 vault/mount.go diff --git a/vault/core.go b/vault/core.go index 65554ff09c..34a9c633c0 100644 --- a/vault/core.go +++ b/vault/core.go @@ -87,6 +87,10 @@ type Core struct { // the threshold number of parts is available. unlockParts [][]byte + // mounts is loaded after unseal since it is a protected + // configuration + mounts *MountTable + logger *log.Logger } @@ -339,6 +343,13 @@ func (c *Core) Unseal(key []byte) (bool, error) { return false, err } + // Do post-unseal setup + if err := c.postUnseal(); err != nil { + c.logger.Printf("[ERR] core: post-unseal setup failed: %v", err) + c.barrier.Seal() + return false, err + } + // Success! c.logger.Printf("[INFO] core: vault is unsealed") c.sealed = false @@ -357,3 +368,14 @@ func (c *Core) Seal() error { c.sealed = true return c.barrier.Seal() } + +// postUnseal is invoked after the barrier is unsealed, but before +// allowing any user operations. This allows us to setup any state that +// requires the Vault to be unsealed such as mount tables, logical backends, +// credential stores, etc. +func (c *Core) postUnseal() error { + if err := c.loadMounts(); err != nil { + return err + } + return nil +} diff --git a/vault/core_test.go b/vault/core_test.go index d9c1404827..d7d2026235 100644 --- a/vault/core_test.go +++ b/vault/core_test.go @@ -279,7 +279,7 @@ func TestCore_Route_Sealed(t *testing.T) { // Should not route anything req := &Request{ Operation: ReadOperation, - Path: "sys/test", + Path: "sys/mounts", } _, err := c.HandleRequest(req) if err != ErrSealed { diff --git a/vault/mount.go b/vault/mount.go new file mode 100644 index 0000000000..0eb23c870f --- /dev/null +++ b/vault/mount.go @@ -0,0 +1,97 @@ +package vault + +import ( + "encoding/json" + "errors" +) + +const ( + // coreMountConfigPath is used to store the mount configuration. + // Mounts are protected within the Vault itself, which means they + // can only be viewed or modified after an unseal. + coreMountConfigPath = "core/mounts" +) + +// MountTable is used to represent the internal mount table +type MountTable struct { + Entries []*MountEntry `json:"entries"` +} + +// MountEntry is used to represent a mount table entry +type MountEntry struct { + Path string `json:"path"` // Mount Path + Type string `json:"type"` // Logical backend Type + Description string `json:"description"` // User-provided description + UUID string `json:"uuid"` // Barrier view UUID +} + +// loadMounts is invoked as part of postUnseal to load the mount table +func (c *Core) loadMounts() error { + // Load the existing mount table + raw, err := c.barrier.Get(coreMountConfigPath) + if err != nil { + c.logger.Printf("[ERR] core: failed to read mount table: %v", err) + return errors.New("failed to setup mount table") + } + if raw != nil { + if err := json.Unmarshal(raw.Value, c.mounts); err != nil { + c.logger.Printf("[ERR] core: failed to decode mount table: %v", err) + return errors.New("failed to setup mount table") + } + } + + // Done if we have restored the mount table + if c.mounts != nil { + return nil + } + + // Create and persist the default mount table + c.mounts = defaultMountTable() + if err := c.persistMounts(); err != nil { + return errors.New("failed to setup mount table") + } + return nil +} + +// persistMounts is used to persist the mount table after modification +func (c *Core) persistMounts() error { + // Marshal the table + raw, err := json.Marshal(c.mounts) + if err != nil { + c.logger.Printf("[ERR] core: failed to encode mount table: %v", err) + return err + } + + // Create an entry + entry := &Entry{ + Key: coreMountConfigPath, + Value: raw, + } + + // Write to the physical backend + if err := c.barrier.Put(entry); err != nil { + c.logger.Printf("[ERR] core: failed to persist mount table: %v", err) + return err + } + return nil +} + +// defaultMountTable creates a default mount table +func defaultMountTable() *MountTable { + table := &MountTable{} + genericMount := &MountEntry{ + Path: "secret/", + Type: "generic", + Description: "generic secret storage", + UUID: generateUUID(), + } + sysMount := &MountEntry{ + Path: "sys/", + Type: "system", + Description: "system endpoints used for control, policy and debugging", + UUID: generateUUID(), + } + table.Entries = append(table.Entries, genericMount) + table.Entries = append(table.Entries, sysMount) + return table +}