Create and persist human-friendly-ish mount accessors (#2918)

This commit is contained in:
Jeff Mitchell
2017-06-26 18:14:36 +01:00
committed by GitHub
parent 8b85fc5cc2
commit 997da9ae39
16 changed files with 240 additions and 46 deletions

View File

@@ -90,6 +90,7 @@ type EnableAuthOptions struct {
type AuthMount struct { type AuthMount struct {
Type string `json:"type" structs:"type" mapstructure:"type"` Type string `json:"type" structs:"type" mapstructure:"type"`
Description string `json:"description" structs:"description" mapstructure:"description"` Description string `json:"description" structs:"description" mapstructure:"description"`
Accessor string `json:"accessor" structs:"accessor" mapstructure:"accessor"`
Config AuthConfigOutput `json:"config" structs:"config" mapstructure:"config"` Config AuthConfigOutput `json:"config" structs:"config" mapstructure:"config"`
Local bool `json:"local" structs:"local" mapstructure:"local"` Local bool `json:"local" structs:"local" mapstructure:"local"`
} }

View File

@@ -135,6 +135,7 @@ type MountConfigInput struct {
type MountOutput struct { type MountOutput struct {
Type string `json:"type" structs:"type"` Type string `json:"type" structs:"type"`
Description string `json:"description" structs:"description"` Description string `json:"description" structs:"description"`
Accessor string `json:"accessor" structs:"accessor"`
Config MountConfigOutput `json:"config" structs:"config"` Config MountConfigOutput `json:"config" structs:"config"`
Local bool `json:"local" structs:"local"` Local bool `json:"local" structs:"local"`
} }

View File

@@ -316,7 +316,7 @@ func (c *AuthCommand) listMethods() int {
} }
sort.Strings(paths) sort.Strings(paths)
columns := []string{"Path | Type | Default TTL | Max TTL | Replication Behavior | Description"} columns := []string{"Path | Type | Accessor | Default TTL | Max TTL | Replication Behavior | Description"}
for _, path := range paths { for _, path := range paths {
auth := auth[path] auth := auth[path]
defTTL := "system" defTTL := "system"
@@ -332,7 +332,7 @@ func (c *AuthCommand) listMethods() int {
replicatedBehavior = "local" replicatedBehavior = "local"
} }
columns = append(columns, fmt.Sprintf( columns = append(columns, fmt.Sprintf(
"%s | %s | %s | %s | %s | %s", path, auth.Type, defTTL, maxTTL, replicatedBehavior, auth.Description)) "%s | %s | %s | %s | %s | %s | %s", path, auth.Type, auth.Accessor, defTTL, maxTTL, replicatedBehavior, auth.Description))
} }
c.Ui.Output(columnize.SimpleFormat(columns)) c.Ui.Output(columnize.SimpleFormat(columns))

View File

@@ -42,7 +42,7 @@ func (c *MountsCommand) Run(args []string) int {
} }
sort.Strings(paths) sort.Strings(paths)
columns := []string{"Path | Type | Default TTL | Max TTL | Force No Cache | Replication Behavior | Description"} columns := []string{"Path | Type | Accessor | Default TTL | Max TTL | Force No Cache | Replication Behavior | Description"}
for _, path := range paths { for _, path := range paths {
mount := mounts[path] mount := mounts[path]
defTTL := "system" defTTL := "system"
@@ -68,7 +68,7 @@ func (c *MountsCommand) Run(args []string) int {
replicatedBehavior = "local" replicatedBehavior = "local"
} }
columns = append(columns, fmt.Sprintf( columns = append(columns, fmt.Sprintf(
"%s | %s | %s | %s | %v | %s | %s", path, mount.Type, defTTL, maxTTL, "%s | %s | %s | %s | %s | %v | %s | %s", path, mount.Type, mount.Accessor, defTTL, maxTTL,
mount.Config.ForceNoCache, replicatedBehavior, mount.Description)) mount.Config.ForceNoCache, replicatedBehavior, mount.Description))
} }

View File

@@ -221,6 +221,13 @@ func TestSysMounts_headerAuth(t *testing.T) {
testResponseBody(t, resp, &actual) testResponseBody(t, resp, &actual)
expected["request_id"] = actual["request_id"] expected["request_id"] = actual["request_id"]
for k, v := range actual["data"].(map[string]interface{}) {
if v.(map[string]interface{})["accessor"] == "" {
t.Fatalf("no accessor from %s", k)
}
expected[k].(map[string]interface{})["accessor"] = v.(map[string]interface{})["accessor"]
expected["data"].(map[string]interface{})[k].(map[string]interface{})["accessor"] = v.(map[string]interface{})["accessor"]
}
if !reflect.DeepEqual(actual, expected) { if !reflect.DeepEqual(actual, expected) {
t.Fatalf("bad:\nExpected: %#v\nActual: %#v\n", expected, actual) t.Fatalf("bad:\nExpected: %#v\nActual: %#v\n", expected, actual)

View File

@@ -49,6 +49,13 @@ func TestSysAuth(t *testing.T) {
testResponseBody(t, resp, &actual) testResponseBody(t, resp, &actual)
expected["request_id"] = actual["request_id"] expected["request_id"] = actual["request_id"]
for k, v := range actual["data"].(map[string]interface{}) {
if v.(map[string]interface{})["accessor"] == "" {
t.Fatalf("no accessor from %s", k)
}
expected[k].(map[string]interface{})["accessor"] = v.(map[string]interface{})["accessor"]
expected["data"].(map[string]interface{})[k].(map[string]interface{})["accessor"] = v.(map[string]interface{})["accessor"]
}
if !reflect.DeepEqual(actual, expected) { if !reflect.DeepEqual(actual, expected) {
t.Fatalf("bad: expected:%#v\nactual:%#v", expected, actual) t.Fatalf("bad: expected:%#v\nactual:%#v", expected, actual)
@@ -120,6 +127,13 @@ func TestSysEnableAuth(t *testing.T) {
testResponseBody(t, resp, &actual) testResponseBody(t, resp, &actual)
expected["request_id"] = actual["request_id"] expected["request_id"] = actual["request_id"]
for k, v := range actual["data"].(map[string]interface{}) {
if v.(map[string]interface{})["accessor"] == "" {
t.Fatalf("no accessor from %s", k)
}
expected[k].(map[string]interface{})["accessor"] = v.(map[string]interface{})["accessor"]
expected["data"].(map[string]interface{})[k].(map[string]interface{})["accessor"] = v.(map[string]interface{})["accessor"]
}
if !reflect.DeepEqual(actual, expected) { if !reflect.DeepEqual(actual, expected) {
t.Fatalf("bad: expected:%#v\nactual:%#v", expected, actual) t.Fatalf("bad: expected:%#v\nactual:%#v", expected, actual)
@@ -176,6 +190,13 @@ func TestSysDisableAuth(t *testing.T) {
testResponseBody(t, resp, &actual) testResponseBody(t, resp, &actual)
expected["request_id"] = actual["request_id"] expected["request_id"] = actual["request_id"]
for k, v := range actual["data"].(map[string]interface{}) {
if v.(map[string]interface{})["accessor"] == "" {
t.Fatalf("no accessor from %s", k)
}
expected[k].(map[string]interface{})["accessor"] = v.(map[string]interface{})["accessor"]
expected["data"].(map[string]interface{})[k].(map[string]interface{})["accessor"] = v.(map[string]interface{})["accessor"]
}
if !reflect.DeepEqual(actual, expected) { if !reflect.DeepEqual(actual, expected) {
t.Fatalf("bad: expected:%#v\nactual:%#v", expected, actual) t.Fatalf("bad: expected:%#v\nactual:%#v", expected, actual)

View File

@@ -91,6 +91,14 @@ func TestSysMounts(t *testing.T) {
testResponseStatus(t, resp, 200) testResponseStatus(t, resp, 200)
testResponseBody(t, resp, &actual) testResponseBody(t, resp, &actual)
expected["request_id"] = actual["request_id"] expected["request_id"] = actual["request_id"]
for k, v := range actual["data"].(map[string]interface{}) {
if v.(map[string]interface{})["accessor"] == "" {
t.Fatalf("no accessor from %s", k)
}
expected[k].(map[string]interface{})["accessor"] = v.(map[string]interface{})["accessor"]
expected["data"].(map[string]interface{})[k].(map[string]interface{})["accessor"] = v.(map[string]interface{})["accessor"]
}
if !reflect.DeepEqual(actual, expected) { if !reflect.DeepEqual(actual, expected) {
t.Fatalf("bad: %#v", actual) t.Fatalf("bad: %#v", actual)
} }
@@ -204,6 +212,14 @@ func TestSysMount(t *testing.T) {
testResponseStatus(t, resp, 200) testResponseStatus(t, resp, 200)
testResponseBody(t, resp, &actual) testResponseBody(t, resp, &actual)
expected["request_id"] = actual["request_id"] expected["request_id"] = actual["request_id"]
for k, v := range actual["data"].(map[string]interface{}) {
if v.(map[string]interface{})["accessor"] == "" {
t.Fatalf("no accessor from %s", k)
}
expected[k].(map[string]interface{})["accessor"] = v.(map[string]interface{})["accessor"]
expected["data"].(map[string]interface{})[k].(map[string]interface{})["accessor"] = v.(map[string]interface{})["accessor"]
}
if !reflect.DeepEqual(actual, expected) { if !reflect.DeepEqual(actual, expected) {
t.Fatalf("bad: %#v", actual) t.Fatalf("bad: %#v", actual)
} }
@@ -339,6 +355,14 @@ func TestSysRemount(t *testing.T) {
testResponseStatus(t, resp, 200) testResponseStatus(t, resp, 200)
testResponseBody(t, resp, &actual) testResponseBody(t, resp, &actual)
expected["request_id"] = actual["request_id"] expected["request_id"] = actual["request_id"]
for k, v := range actual["data"].(map[string]interface{}) {
if v.(map[string]interface{})["accessor"] == "" {
t.Fatalf("no accessor from %s", k)
}
expected[k].(map[string]interface{})["accessor"] = v.(map[string]interface{})["accessor"]
expected["data"].(map[string]interface{})[k].(map[string]interface{})["accessor"] = v.(map[string]interface{})["accessor"]
}
if !reflect.DeepEqual(actual, expected) { if !reflect.DeepEqual(actual, expected) {
t.Fatalf("bad: %#v", actual) t.Fatalf("bad: %#v", actual)
} }
@@ -435,6 +459,14 @@ func TestSysUnmount(t *testing.T) {
testResponseStatus(t, resp, 200) testResponseStatus(t, resp, 200)
testResponseBody(t, resp, &actual) testResponseBody(t, resp, &actual)
expected["request_id"] = actual["request_id"] expected["request_id"] = actual["request_id"]
for k, v := range actual["data"].(map[string]interface{}) {
if v.(map[string]interface{})["accessor"] == "" {
t.Fatalf("no accessor from %s", k)
}
expected[k].(map[string]interface{})["accessor"] = v.(map[string]interface{})["accessor"]
expected["data"].(map[string]interface{})[k].(map[string]interface{})["accessor"] = v.(map[string]interface{})["accessor"]
}
if !reflect.DeepEqual(actual, expected) { if !reflect.DeepEqual(actual, expected) {
t.Fatalf("bad: %#v", actual) t.Fatalf("bad: %#v", actual)
} }
@@ -548,6 +580,14 @@ func TestSysTuneMount(t *testing.T) {
testResponseStatus(t, resp, 200) testResponseStatus(t, resp, 200)
testResponseBody(t, resp, &actual) testResponseBody(t, resp, &actual)
expected["request_id"] = actual["request_id"] expected["request_id"] = actual["request_id"]
for k, v := range actual["data"].(map[string]interface{}) {
if v.(map[string]interface{})["accessor"] == "" {
t.Fatalf("no accessor from %s", k)
}
expected[k].(map[string]interface{})["accessor"] = v.(map[string]interface{})["accessor"]
expected["data"].(map[string]interface{})[k].(map[string]interface{})["accessor"] = v.(map[string]interface{})["accessor"]
}
if !reflect.DeepEqual(actual, expected) { if !reflect.DeepEqual(actual, expected) {
t.Fatalf("bad: %#v", actual) t.Fatalf("bad: %#v", actual)
} }
@@ -683,6 +723,14 @@ func TestSysTuneMount(t *testing.T) {
testResponseStatus(t, resp, 200) testResponseStatus(t, resp, 200)
testResponseBody(t, resp, &actual) testResponseBody(t, resp, &actual)
expected["request_id"] = actual["request_id"] expected["request_id"] = actual["request_id"]
for k, v := range actual["data"].(map[string]interface{}) {
if v.(map[string]interface{})["accessor"] == "" {
t.Fatalf("no accessor from %s", k)
}
expected[k].(map[string]interface{})["accessor"] = v.(map[string]interface{})["accessor"]
expected["data"].(map[string]interface{})[k].(map[string]interface{})["accessor"] = v.(map[string]interface{})["accessor"]
}
if !reflect.DeepEqual(actual, expected) { if !reflect.DeepEqual(actual, expected) {
t.Fatalf("bad:\nExpected: %#v\nActual:%#v", expected, actual) t.Fatalf("bad:\nExpected: %#v\nActual:%#v", expected, actual)
} }

View File

@@ -79,6 +79,13 @@ func (c *Core) enableAudit(entry *MountEntry) error {
} }
entry.UUID = entryUUID entry.UUID = entryUUID
} }
if entry.Accessor == "" {
accessor, err := c.generateMountAccessor("audit_" + entry.Type)
if err != nil {
return err
}
entry.Accessor = accessor
}
viewPath := auditBarrierPrefix + entry.UUID + "/" viewPath := auditBarrierPrefix + entry.UUID + "/"
view := NewBarrierView(c.barrier, viewPath) view := NewBarrierView(c.barrier, viewPath)
@@ -201,6 +208,14 @@ func (c *Core) loadAudits() error {
entry.Table = c.audit.Type entry.Table = c.audit.Type
needPersist = true needPersist = true
} }
if entry.Accessor == "" {
accessor, err := c.generateMountAccessor("audit_" + entry.Type)
if err != nil {
return err
}
entry.Accessor = accessor
needPersist = true
}
} }
if !needPersist { if !needPersist {

View File

@@ -224,12 +224,14 @@ func TestCore_EnableAudit_Local(t *testing.T) {
Path: "noop/", Path: "noop/",
Type: "noop", Type: "noop",
UUID: "abcd", UUID: "abcd",
Accessor: "noop-abcd",
}, },
&MountEntry{ &MountEntry{
Table: auditTableType, Table: auditTableType,
Path: "noop2/", Path: "noop2/",
Type: "noop", Type: "noop",
UUID: "bcde", UUID: "bcde",
Accessor: "noop-bcde",
}, },
}, },
} }

View File

@@ -85,7 +85,13 @@ func (c *Core) enableCredential(entry *MountEntry) error {
} }
entry.UUID = entryUUID entry.UUID = entryUUID
} }
if entry.Accessor == "" {
accessor, err := c.generateMountAccessor("auth_" + entry.Type)
if err != nil {
return err
}
entry.Accessor = accessor
}
viewPath := credentialBarrierPrefix + entry.UUID + "/" viewPath := credentialBarrierPrefix + entry.UUID + "/"
view := NewBarrierView(c.barrier, viewPath) view := NewBarrierView(c.barrier, viewPath)
sysView := c.mountEntrySysView(entry) sysView := c.mountEntrySysView(entry)
@@ -283,13 +289,21 @@ func (c *Core) loadCredentials() error {
entry.Table = c.auth.Type entry.Table = c.auth.Type
needPersist = true needPersist = true
} }
if entry.Accessor == "" {
accessor, err := c.generateMountAccessor("auth_" + entry.Type)
if err != nil {
return err
}
entry.Accessor = accessor
needPersist = true
}
} }
if !needPersist { if !needPersist {
return nil return nil
} }
} else { } else {
c.auth = defaultAuthTable() c.auth = c.defaultAuthTable()
} }
if err := c.persistAuth(c.auth, false); err != nil { if err := c.persistAuth(c.auth, false); err != nil {
@@ -485,7 +499,7 @@ func (c *Core) newCredentialBackend(
} }
// defaultAuthTable creates a default auth table // defaultAuthTable creates a default auth table
func defaultAuthTable() *MountTable { func (c *Core) defaultAuthTable() *MountTable {
table := &MountTable{ table := &MountTable{
Type: credentialTableType, Type: credentialTableType,
} }
@@ -493,12 +507,17 @@ func defaultAuthTable() *MountTable {
if err != nil { if err != nil {
panic(fmt.Sprintf("could not generate UUID for default auth table token entry: %v", err)) panic(fmt.Sprintf("could not generate UUID for default auth table token entry: %v", err))
} }
tokenAccessor, err := c.generateMountAccessor("auth_token")
if err != nil {
panic(fmt.Sprintf("could not generate accessor for default auth table token entry: %v", err))
}
tokenAuth := &MountEntry{ tokenAuth := &MountEntry{
Table: credentialTableType, Table: credentialTableType,
Path: "token/", Path: "token/",
Type: "token", Type: "token",
Description: "token based credentials", Description: "token based credentials",
UUID: tokenUUID, UUID: tokenUUID,
Accessor: tokenAccessor,
} }
table.Entries = append(table.Entries, tokenAuth) table.Entries = append(table.Entries, tokenAuth)
return table return table

View File

@@ -103,12 +103,14 @@ func TestCore_EnableCredential_Local(t *testing.T) {
Path: "noop/", Path: "noop/",
Type: "noop", Type: "noop",
UUID: "abcd", UUID: "abcd",
Accessor: "noop-abcd",
}, },
&MountEntry{ &MountEntry{
Table: credentialTableType, Table: credentialTableType,
Path: "noop2/", Path: "noop2/",
Type: "noop", Type: "noop",
UUID: "bcde", UUID: "bcde",
Accessor: "noop-bcde",
}, },
}, },
} }
@@ -347,7 +349,8 @@ func TestCore_DisableCredential_Cleanup(t *testing.T) {
} }
func TestDefaultAuthTable(t *testing.T) { func TestDefaultAuthTable(t *testing.T) {
table := defaultAuthTable() c, _, _ := TestCoreUnsealed(t)
table := c.defaultAuthTable()
verifyDefaultAuthTable(t, table) verifyDefaultAuthTable(t, table)
} }

View File

@@ -1160,6 +1160,7 @@ func (b *SystemBackend) handleMountTable(
info := map[string]interface{}{ info := map[string]interface{}{
"type": entry.Type, "type": entry.Type,
"description": entry.Description, "description": entry.Description,
"accessor": entry.Accessor,
"config": map[string]interface{}{ "config": map[string]interface{}{
"default_lease_ttl": int64(entry.Config.DefaultLeaseTTL.Seconds()), "default_lease_ttl": int64(entry.Config.DefaultLeaseTTL.Seconds()),
"max_lease_ttl": int64(entry.Config.MaxLeaseTTL.Seconds()), "max_lease_ttl": int64(entry.Config.MaxLeaseTTL.Seconds()),
@@ -1656,6 +1657,7 @@ func (b *SystemBackend) handleAuthTable(
info := map[string]interface{}{ info := map[string]interface{}{
"type": entry.Type, "type": entry.Type,
"description": entry.Description, "description": entry.Description,
"accessor": entry.Accessor,
"config": map[string]interface{}{ "config": map[string]interface{}{
"default_lease_ttl": int64(entry.Config.DefaultLeaseTTL.Seconds()), "default_lease_ttl": int64(entry.Config.DefaultLeaseTTL.Seconds()),
"max_lease_ttl": int64(entry.Config.MaxLeaseTTL.Seconds()), "max_lease_ttl": int64(entry.Config.MaxLeaseTTL.Seconds()),

View File

@@ -115,6 +115,7 @@ func TestSystemBackend_mounts(t *testing.T) {
"secret/": map[string]interface{}{ "secret/": map[string]interface{}{
"type": "generic", "type": "generic",
"description": "generic secret storage", "description": "generic secret storage",
"accessor": resp.Data["secret/"].(map[string]interface{})["accessor"],
"config": map[string]interface{}{ "config": map[string]interface{}{
"default_lease_ttl": resp.Data["secret/"].(map[string]interface{})["config"].(map[string]interface{})["default_lease_ttl"].(int64), "default_lease_ttl": resp.Data["secret/"].(map[string]interface{})["config"].(map[string]interface{})["default_lease_ttl"].(int64),
"max_lease_ttl": resp.Data["secret/"].(map[string]interface{})["config"].(map[string]interface{})["max_lease_ttl"].(int64), "max_lease_ttl": resp.Data["secret/"].(map[string]interface{})["config"].(map[string]interface{})["max_lease_ttl"].(int64),
@@ -125,6 +126,7 @@ func TestSystemBackend_mounts(t *testing.T) {
"sys/": map[string]interface{}{ "sys/": map[string]interface{}{
"type": "system", "type": "system",
"description": "system endpoints used for control, policy and debugging", "description": "system endpoints used for control, policy and debugging",
"accessor": resp.Data["sys/"].(map[string]interface{})["accessor"],
"config": map[string]interface{}{ "config": map[string]interface{}{
"default_lease_ttl": resp.Data["sys/"].(map[string]interface{})["config"].(map[string]interface{})["default_lease_ttl"].(int64), "default_lease_ttl": resp.Data["sys/"].(map[string]interface{})["config"].(map[string]interface{})["default_lease_ttl"].(int64),
"max_lease_ttl": resp.Data["sys/"].(map[string]interface{})["config"].(map[string]interface{})["max_lease_ttl"].(int64), "max_lease_ttl": resp.Data["sys/"].(map[string]interface{})["config"].(map[string]interface{})["max_lease_ttl"].(int64),
@@ -135,6 +137,7 @@ func TestSystemBackend_mounts(t *testing.T) {
"cubbyhole/": map[string]interface{}{ "cubbyhole/": map[string]interface{}{
"description": "per-token private secret storage", "description": "per-token private secret storage",
"type": "cubbyhole", "type": "cubbyhole",
"accessor": resp.Data["cubbyhole/"].(map[string]interface{})["accessor"],
"config": map[string]interface{}{ "config": map[string]interface{}{
"default_lease_ttl": resp.Data["cubbyhole/"].(map[string]interface{})["config"].(map[string]interface{})["default_lease_ttl"].(int64), "default_lease_ttl": resp.Data["cubbyhole/"].(map[string]interface{})["config"].(map[string]interface{})["default_lease_ttl"].(int64),
"max_lease_ttl": resp.Data["cubbyhole/"].(map[string]interface{})["config"].(map[string]interface{})["max_lease_ttl"].(int64), "max_lease_ttl": resp.Data["cubbyhole/"].(map[string]interface{})["config"].(map[string]interface{})["max_lease_ttl"].(int64),
@@ -1113,6 +1116,7 @@ func TestSystemBackend_authTable(t *testing.T) {
"token/": map[string]interface{}{ "token/": map[string]interface{}{
"type": "token", "type": "token",
"description": "token based credentials", "description": "token based credentials",
"accessor": resp.Data["token/"].(map[string]interface{})["accessor"],
"config": map[string]interface{}{ "config": map[string]interface{}{
"default_lease_ttl": int64(0), "default_lease_ttl": int64(0),
"max_lease_ttl": int64(0), "max_lease_ttl": int64(0),

View File

@@ -66,6 +66,22 @@ var (
} }
) )
func (c *Core) generateMountAccessor(entryType string) (string, error) {
var accessor string
for {
randBytes, err := uuid.GenerateRandomBytes(4)
if err != nil {
return "", err
}
accessor = fmt.Sprintf("%s_%s", entryType, fmt.Sprintf("%08x", randBytes[0:4]))
if entry := c.router.MatchingMountByAccessor(accessor); entry == nil {
break
}
}
return accessor, nil
}
// MountTable is used to represent the internal mount table // MountTable is used to represent the internal mount table
type MountTable struct { type MountTable struct {
Type string `json:"type"` Type string `json:"type"`
@@ -139,6 +155,7 @@ type MountEntry struct {
Type string `json:"type"` // Logical backend Type Type string `json:"type"` // Logical backend Type
Description string `json:"description"` // User-provided description Description string `json:"description"` // User-provided description
UUID string `json:"uuid"` // Barrier view UUID UUID string `json:"uuid"` // Barrier view UUID
Accessor string `json:"accessor"` // Unique but more human-friendly ID. Does not change, not used for any sensitive things (like as a salt, which the UUID sometimes is).
Config MountConfig `json:"config"` // Configuration related to this mount (but not backend-derived) Config MountConfig `json:"config"` // Configuration related to this mount (but not backend-derived)
Options map[string]string `json:"options"` // Backend options Options map[string]string `json:"options"` // Backend options
Local bool `json:"local"` // Local mounts are not replicated or affected by replication Local bool `json:"local"` // Local mounts are not replicated or affected by replication
@@ -164,6 +181,7 @@ func (e *MountEntry) Clone() *MountEntry {
Type: e.Type, Type: e.Type,
Description: e.Description, Description: e.Description,
UUID: e.UUID, UUID: e.UUID,
Accessor: e.Accessor,
Config: e.Config, Config: e.Config,
Options: optClone, Options: optClone,
Local: e.Local, Local: e.Local,
@@ -208,6 +226,13 @@ func (c *Core) mount(entry *MountEntry) error {
} }
entry.UUID = entryUUID entry.UUID = entryUUID
} }
if entry.Accessor == "" {
accessor, err := c.generateMountAccessor(entry.Type)
if err != nil {
return err
}
entry.Accessor = accessor
}
viewPath := backendBarrierPrefix + entry.UUID + "/" viewPath := backendBarrierPrefix + entry.UUID + "/"
view := NewBarrierView(c.barrier, viewPath) view := NewBarrierView(c.barrier, viewPath)
sysView := c.mountEntrySysView(entry) sysView := c.mountEntrySysView(entry)
@@ -504,7 +529,7 @@ func (c *Core) loadMounts() error {
needPersist = true needPersist = true
} }
for _, requiredMount := range requiredMountTable().Entries { for _, requiredMount := range c.requiredMountTable().Entries {
foundRequired := false foundRequired := false
for _, coreMount := range c.mounts.Entries { for _, coreMount := range c.mounts.Entries {
if coreMount.Type == requiredMount.Type { if coreMount.Type == requiredMount.Type {
@@ -535,6 +560,14 @@ func (c *Core) loadMounts() error {
entry.Table = c.mounts.Type entry.Table = c.mounts.Type
needPersist = true needPersist = true
} }
if entry.Accessor == "" {
accessor, err := c.generateMountAccessor(entry.Type)
if err != nil {
return err
}
entry.Accessor = accessor
needPersist = true
}
} }
// Done if we have restored the mount table and we don't need // Done if we have restored the mount table and we don't need
@@ -544,7 +577,7 @@ func (c *Core) loadMounts() error {
} }
} else { } else {
// Create and persist the default mount table // Create and persist the default mount table
c.mounts = defaultMountTable() c.mounts = c.defaultMountTable()
} }
if err := c.persistMounts(c.mounts, false); err != nil { if err := c.persistMounts(c.mounts, false); err != nil {
@@ -745,13 +778,17 @@ func (c *Core) mountEntrySysView(entry *MountEntry) logical.SystemView {
} }
// defaultMountTable creates a default mount table // defaultMountTable creates a default mount table
func defaultMountTable() *MountTable { func (c *Core) defaultMountTable() *MountTable {
table := &MountTable{ table := &MountTable{
Type: mountTableType, Type: mountTableType,
} }
mountUUID, err := uuid.GenerateUUID() mountUUID, err := uuid.GenerateUUID()
if err != nil { if err != nil {
panic(fmt.Sprintf("could not create default mount table UUID: %v", err)) panic(fmt.Sprintf("could not create default secret mount UUID: %v", err))
}
mountAccessor, err := c.generateMountAccessor("generic")
if err != nil {
panic(fmt.Sprintf("could not generate default secret mount accessor: %v", err))
} }
genericMount := &MountEntry{ genericMount := &MountEntry{
Table: mountTableType, Table: mountTableType,
@@ -759,15 +796,16 @@ func defaultMountTable() *MountTable {
Type: "generic", Type: "generic",
Description: "generic secret storage", Description: "generic secret storage",
UUID: mountUUID, UUID: mountUUID,
Accessor: mountAccessor,
} }
table.Entries = append(table.Entries, genericMount) table.Entries = append(table.Entries, genericMount)
table.Entries = append(table.Entries, requiredMountTable().Entries...) table.Entries = append(table.Entries, c.requiredMountTable().Entries...)
return table return table
} }
// requiredMountTable() creates a mount table with entries required // requiredMountTable() creates a mount table with entries required
// to be available // to be available
func requiredMountTable() *MountTable { func (c *Core) requiredMountTable() *MountTable {
table := &MountTable{ table := &MountTable{
Type: mountTableType, Type: mountTableType,
} }
@@ -775,12 +813,17 @@ func requiredMountTable() *MountTable {
if err != nil { if err != nil {
panic(fmt.Sprintf("could not create cubbyhole UUID: %v", err)) panic(fmt.Sprintf("could not create cubbyhole UUID: %v", err))
} }
cubbyholeAccessor, err := c.generateMountAccessor("cubbyhole")
if err != nil {
panic(fmt.Sprintf("could not generate cubbyhole accessor: %v", err))
}
cubbyholeMount := &MountEntry{ cubbyholeMount := &MountEntry{
Table: mountTableType, Table: mountTableType,
Path: "cubbyhole/", Path: "cubbyhole/",
Type: "cubbyhole", Type: "cubbyhole",
Description: "per-token private secret storage", Description: "per-token private secret storage",
UUID: cubbyholeUUID, UUID: cubbyholeUUID,
Accessor: cubbyholeAccessor,
Local: true, Local: true,
} }
@@ -788,12 +831,17 @@ func requiredMountTable() *MountTable {
if err != nil { if err != nil {
panic(fmt.Sprintf("could not create sys UUID: %v", err)) panic(fmt.Sprintf("could not create sys UUID: %v", err))
} }
sysAccessor, err := c.generateMountAccessor("system")
if err != nil {
panic(fmt.Sprintf("could not generate sys accessor: %v", err))
}
sysMount := &MountEntry{ sysMount := &MountEntry{
Table: mountTableType, Table: mountTableType,
Path: "sys/", Path: "sys/",
Type: "system", Type: "system",
Description: "system endpoints used for control, policy and debugging", Description: "system endpoints used for control, policy and debugging",
UUID: sysUUID, UUID: sysUUID,
Accessor: sysAccessor,
} }
table.Entries = append(table.Entries, cubbyholeMount) table.Entries = append(table.Entries, cubbyholeMount)
table.Entries = append(table.Entries, sysMount) table.Entries = append(table.Entries, sysMount)

View File

@@ -97,12 +97,14 @@ func TestCore_Mount_Local(t *testing.T) {
Path: "noop/", Path: "noop/",
Type: "generic", Type: "generic",
UUID: "abcd", UUID: "abcd",
Accessor: "generic-abcd",
}, },
&MountEntry{ &MountEntry{
Table: mountTableType, Table: mountTableType,
Path: "noop2/", Path: "noop2/",
Type: "generic", Type: "generic",
UUID: "bcde", UUID: "bcde",
Accessor: "generic-bcde",
}, },
}, },
} }
@@ -426,7 +428,8 @@ func TestCore_Remount_Protected(t *testing.T) {
} }
func TestDefaultMountTable(t *testing.T) { func TestDefaultMountTable(t *testing.T) {
table := defaultMountTable() c, _, _ := TestCoreUnsealed(t)
table := c.defaultMountTable()
verifyDefaultTable(t, table) verifyDefaultTable(t, table)
} }

View File

@@ -17,6 +17,7 @@ type Router struct {
l sync.RWMutex l sync.RWMutex
root *radix.Tree root *radix.Tree
mountUUIDCache *radix.Tree mountUUIDCache *radix.Tree
mountAccessorCache *radix.Tree
tokenStoreSalt *salt.Salt tokenStoreSalt *salt.Salt
// storagePrefix maps the prefix used for storage (ala the BarrierView) // storagePrefix maps the prefix used for storage (ala the BarrierView)
@@ -31,6 +32,7 @@ func NewRouter() *Router {
root: radix.New(), root: radix.New(),
storagePrefix: radix.New(), storagePrefix: radix.New(),
mountUUIDCache: radix.New(), mountUUIDCache: radix.New(),
mountAccessorCache: radix.New(),
} }
return r return r
} }
@@ -80,6 +82,7 @@ func (r *Router) Mount(backend logical.Backend, prefix string, mountEntry *Mount
r.root.Insert(prefix, re) r.root.Insert(prefix, re)
r.storagePrefix.Insert(storageView.prefix, re) r.storagePrefix.Insert(storageView.prefix, re)
r.mountUUIDCache.Insert(re.mountEntry.UUID, re.mountEntry) r.mountUUIDCache.Insert(re.mountEntry.UUID, re.mountEntry)
r.mountAccessorCache.Insert(re.mountEntry.Accessor, re.mountEntry)
return nil return nil
} }
@@ -103,6 +106,7 @@ func (r *Router) Unmount(prefix string) error {
r.root.Delete(prefix) r.root.Delete(prefix)
r.storagePrefix.Delete(re.storageView.prefix) r.storagePrefix.Delete(re.storageView.prefix)
r.mountUUIDCache.Delete(re.mountEntry.UUID) r.mountUUIDCache.Delete(re.mountEntry.UUID)
r.mountAccessorCache.Delete(re.mountEntry.Accessor)
return nil return nil
} }
@@ -163,6 +167,22 @@ func (r *Router) MatchingMountByUUID(mountID string) *MountEntry {
return raw.(*MountEntry) return raw.(*MountEntry)
} }
func (r *Router) MatchingMountByAccessor(mountAccessor string) *MountEntry {
if mountAccessor == "" {
return nil
}
r.l.RLock()
defer r.l.RUnlock()
_, raw, ok := r.mountAccessorCache.LongestPrefix(mountAccessor)
if !ok {
return nil
}
return raw.(*MountEntry)
}
// MatchingMount returns the mount prefix that would be used for a path // MatchingMount returns the mount prefix that would be used for a path
func (r *Router) MatchingMount(path string) string { func (r *Router) MatchingMount(path string) string {
r.l.RLock() r.l.RLock()