Sync
This commit is contained in:
parent
d6a9a770c1
commit
47dae8ffc7
|
@ -41,6 +41,30 @@ const (
|
|||
SudoCapabilityInt
|
||||
)
|
||||
|
||||
type PolicyType uint32
|
||||
|
||||
const (
|
||||
PolicyTypeACL PolicyType = iota
|
||||
PolicyTypeRGP
|
||||
PolicyTypeEGP
|
||||
|
||||
// Triggers a lookup in the map to figure out if ACL or RGP
|
||||
PolicyTypeToken
|
||||
)
|
||||
|
||||
func (p PolicyType) String() string {
|
||||
switch p {
|
||||
case PolicyTypeACL:
|
||||
return "acl"
|
||||
case PolicyTypeRGP:
|
||||
return "rgp"
|
||||
case PolicyTypeEGP:
|
||||
return "egp"
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
var (
|
||||
cap2Int = map[string]uint32{
|
||||
DenyCapability: DenyCapabilityInt,
|
||||
|
@ -56,28 +80,30 @@ var (
|
|||
// Policy is used to represent the policy specified by
|
||||
// an ACL configuration.
|
||||
type Policy struct {
|
||||
Name string `hcl:"name"`
|
||||
Paths []*PathCapabilities `hcl:"-"`
|
||||
Raw string
|
||||
Name string `hcl:"name"`
|
||||
Paths []*PathRules `hcl:"-"`
|
||||
Raw string
|
||||
Type PolicyType
|
||||
}
|
||||
|
||||
// PathCapabilities represents a policy for a path in the namespace.
|
||||
type PathCapabilities struct {
|
||||
|
||||
// PathRules represents a policy for a path in the namespace.
|
||||
type PathRules struct {
|
||||
Prefix string
|
||||
Policy string
|
||||
Permissions *Permissions
|
||||
Permissions *ACLPermissions
|
||||
Glob bool
|
||||
Capabilities []string
|
||||
|
||||
// These keys are used at the top level to make the HCL nicer; we store in
|
||||
// the Permissions object though
|
||||
// the ACLPermissions object though
|
||||
MinWrappingTTLHCL interface{} `hcl:"min_wrapping_ttl"`
|
||||
MaxWrappingTTLHCL interface{} `hcl:"max_wrapping_ttl"`
|
||||
AllowedParametersHCL map[string][]interface{} `hcl:"allowed_parameters"`
|
||||
DeniedParametersHCL map[string][]interface{} `hcl:"denied_parameters"`
|
||||
}
|
||||
|
||||
type Permissions struct {
|
||||
type ACLPermissions struct {
|
||||
CapabilitiesBitmap uint32
|
||||
MinWrappingTTL time.Duration
|
||||
MaxWrappingTTL time.Duration
|
||||
|
@ -85,8 +111,8 @@ type Permissions struct {
|
|||
DeniedParameters map[string][]interface{}
|
||||
}
|
||||
|
||||
func (p *Permissions) Clone() (*Permissions, error) {
|
||||
ret := &Permissions{
|
||||
func (p *ACLPermissions) Clone() (*ACLPermissions, error) {
|
||||
ret := &ACLPermissions{
|
||||
CapabilitiesBitmap: p.CapabilitiesBitmap,
|
||||
MinWrappingTTL: p.MinWrappingTTL,
|
||||
MaxWrappingTTL: p.MaxWrappingTTL,
|
||||
|
@ -122,7 +148,7 @@ func (p *Permissions) Clone() (*Permissions, error) {
|
|||
// Parse is used to parse the specified ACL rules into an
|
||||
// intermediary set of policies, before being compiled into
|
||||
// the ACL
|
||||
func Parse(rules string) (*Policy, error) {
|
||||
func ParseACLPolicy(rules string) (*Policy, error) {
|
||||
// Parse the rules
|
||||
root, err := hcl.Parse(rules)
|
||||
if err != nil {
|
||||
|
@ -147,6 +173,7 @@ func Parse(rules string) (*Policy, error) {
|
|||
// Create the initial policy and store the raw text of the rules
|
||||
var p Policy
|
||||
p.Raw = rules
|
||||
p.Type = PolicyTypeACL
|
||||
if err := hcl.DecodeObject(&p, list); err != nil {
|
||||
return nil, fmt.Errorf("Failed to parse policy: %s", err)
|
||||
}
|
||||
|
@ -161,7 +188,7 @@ func Parse(rules string) (*Policy, error) {
|
|||
}
|
||||
|
||||
func parsePaths(result *Policy, list *ast.ObjectList) error {
|
||||
paths := make([]*PathCapabilities, 0, len(list.Items))
|
||||
paths := make([]*PathRules, 0, len(list.Items))
|
||||
for _, item := range list.Items {
|
||||
key := "path"
|
||||
if len(item.Keys) > 0 {
|
||||
|
@ -179,10 +206,10 @@ func parsePaths(result *Policy, list *ast.ObjectList) error {
|
|||
return multierror.Prefix(err, fmt.Sprintf("path %q:", key))
|
||||
}
|
||||
|
||||
var pc PathCapabilities
|
||||
var pc PathRules
|
||||
|
||||
// allocate memory so that DecodeObject can initialize the Permissions struct
|
||||
pc.Permissions = new(Permissions)
|
||||
// allocate memory so that DecodeObject can initialize the ACLPermissions struct
|
||||
pc.Permissions = new(ACLPermissions)
|
||||
|
||||
pc.Prefix = key
|
||||
if err := hcl.DecodeObject(&pc, item.Val); err != nil {
|
||||
|
|
|
@ -16,7 +16,7 @@ import (
|
|||
const (
|
||||
// policySubPath is the sub-path used for the policy store
|
||||
// view. This is nested under the system view.
|
||||
policySubPath = "policy/"
|
||||
policyACLSubPath = "policy/"
|
||||
|
||||
// policyCacheSize is the number of policies that are kept cached
|
||||
policyCacheSize = 1024
|
||||
|
@ -125,39 +125,57 @@ var (
|
|||
// PolicyStore is used to provide durable storage of policy, and to
|
||||
// manage ACLs associated with them.
|
||||
type PolicyStore struct {
|
||||
view *BarrierView
|
||||
aclView *BarrierView
|
||||
tokenPoliciesLRU *lru.TwoQueueCache
|
||||
lru *lru.TwoQueueCache
|
||||
// This is used to ensure that writes to the store (acl/rgp) or to the egp
|
||||
// path tree don't happen concurrently. We are okay reading stale data so
|
||||
// long as there aren't concurrent writes.
|
||||
modifyLock *sync.RWMutex
|
||||
// Stores whether a token policy is ACL or RGP
|
||||
policyTypeMap sync.Map
|
||||
}
|
||||
|
||||
// PolicyEntry is used to store a policy by name
|
||||
type PolicyEntry struct {
|
||||
Version int
|
||||
Raw string
|
||||
Type PolicyType
|
||||
}
|
||||
|
||||
// NewPolicyStore creates a new PolicyStore that is backed
|
||||
// using a given view. It used used to durable store and manage named policy.
|
||||
func NewPolicyStore(view *BarrierView, system logical.SystemView) *PolicyStore {
|
||||
p := &PolicyStore{
|
||||
view: view,
|
||||
func NewPolicyStore(baseView *BarrierView, system logical.SystemView) *PolicyStore {
|
||||
ps := &PolicyStore{
|
||||
aclView: baseView.SubView(policyACLSubPath),
|
||||
modifyLock: new(sync.RWMutex),
|
||||
}
|
||||
if !system.CachingDisabled() {
|
||||
cache, _ := lru.New2Q(policyCacheSize)
|
||||
ps.tokenPoliciesLRU = cache
|
||||
cache, _ = lru.New2Q(policyCacheSize)
|
||||
p.lru = cache
|
||||
}
|
||||
|
||||
return p
|
||||
keys, err := logical.CollectKeys(ps.aclView)
|
||||
if err != nil {
|
||||
vlogger.Error("error collecting acl policy keys", "error", err)
|
||||
return nil
|
||||
}
|
||||
for _, key := range keys {
|
||||
ps.policyTypeMap.Store(ps.sanitizeName(key), PolicyTypeACL)
|
||||
}
|
||||
// Special-case root; doesn't exist on disk but does need to be found
|
||||
ps.policyTypeMap.Store("root", PolicyTypeACL)
|
||||
return ps
|
||||
}
|
||||
|
||||
// setupPolicyStore is used to initialize the policy store
|
||||
// when the vault is being unsealed.
|
||||
func (c *Core) setupPolicyStore() error {
|
||||
// Create a sub-view
|
||||
view := c.systemBarrierView.SubView(policySubPath)
|
||||
|
||||
// Create the policy store
|
||||
sysView := &dynamicSystemView{core: c}
|
||||
c.policyStore = NewPolicyStore(view, sysView)
|
||||
c.policyStore = NewPolicyStore(c.systemBarrierView, sysView)
|
||||
|
||||
if c.replicationState.HasState(consts.ReplicationPerformanceSecondary) {
|
||||
// Policies will sync from the primary
|
||||
|
@ -165,7 +183,7 @@ func (c *Core) setupPolicyStore() error {
|
|||
}
|
||||
|
||||
// Ensure that the default policy exists, and if not, create it
|
||||
policy, err := c.policyStore.GetPolicy("default")
|
||||
policy, err := c.policyStore.GetPolicy("default", PolicyTypeACL)
|
||||
if err != nil {
|
||||
return errwrap.Wrapf("error fetching default policy from store: {{err}}", err)
|
||||
}
|
||||
|
@ -177,7 +195,7 @@ func (c *Core) setupPolicyStore() error {
|
|||
}
|
||||
|
||||
// Ensure that the cubbyhole response wrapping policy exists
|
||||
policy, err = c.policyStore.GetPolicy(responseWrappingPolicyName)
|
||||
policy, err = c.policyStore.GetPolicy(responseWrappingPolicyName, PolicyTypeACL)
|
||||
if err != nil {
|
||||
return errwrap.Wrapf("error fetching response-wrapping policy from store: {{err}}", err)
|
||||
}
|
||||
|
@ -198,24 +216,41 @@ func (c *Core) teardownPolicyStore() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (ps *PolicyStore) invalidate(name string) {
|
||||
if ps.lru == nil {
|
||||
// Nothing to do if the cache is not used
|
||||
func (ps *PolicyStore) invalidate(name string, policyType PolicyType) {
|
||||
// This may come with a prefixed "/" due to joining the file path
|
||||
saneName := strings.TrimPrefix(name, "/")
|
||||
|
||||
// We don't lock before removing from the LRU here because the worst that
|
||||
// can happen is we load again if something since added it
|
||||
switch policyType {
|
||||
case PolicyTypeACL:
|
||||
if ps.tokenPoliciesLRU != nil {
|
||||
ps.tokenPoliciesLRU.Remove(saneName)
|
||||
}
|
||||
|
||||
default:
|
||||
// Can't do anything
|
||||
return
|
||||
}
|
||||
|
||||
// This may come with a prefixed "/" due to joining the file path
|
||||
ps.lru.Remove(strings.TrimPrefix(name, "/"))
|
||||
// Force a reload
|
||||
p, err := ps.GetPolicy(name, policyType)
|
||||
if err != nil {
|
||||
vlogger.Error("policy: error fetching policy after invalidation", "name", saneName)
|
||||
}
|
||||
}
|
||||
|
||||
// SetPolicy is used to create or update the given policy
|
||||
func (ps *PolicyStore) SetPolicy(p *Policy) error {
|
||||
defer metrics.MeasureSince([]string{"policy", "set_policy"}, time.Now())
|
||||
if p == nil {
|
||||
return fmt.Errorf("nil policy passed in for storage")
|
||||
}
|
||||
if p.Name == "" {
|
||||
return fmt.Errorf("policy name missing")
|
||||
}
|
||||
// Policies are normalized to lower-case
|
||||
p.Name = strings.ToLower(strings.TrimSpace(p.Name))
|
||||
p.Name = ps.sanitizeName(p.Name)
|
||||
if strutil.StrListContains(immutablePolicies, p.Name) {
|
||||
return fmt.Errorf("cannot update %s policy", p.Name)
|
||||
}
|
||||
|
@ -224,70 +259,131 @@ func (ps *PolicyStore) SetPolicy(p *Policy) error {
|
|||
}
|
||||
|
||||
func (ps *PolicyStore) setPolicyInternal(p *Policy) error {
|
||||
ps.modifyLock.Lock()
|
||||
defer ps.modifyLock.Unlock()
|
||||
// Create the entry
|
||||
entry, err := logical.StorageEntryJSON(p.Name, &PolicyEntry{
|
||||
Version: 2,
|
||||
Raw: p.Raw,
|
||||
Version: 2,
|
||||
Raw: p.Raw,
|
||||
Type: p.Type,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create entry: %v", err)
|
||||
}
|
||||
if err := ps.view.Put(entry); err != nil {
|
||||
return fmt.Errorf("failed to persist policy: %v", err)
|
||||
switch p.Type {
|
||||
case PolicyTypeACL:
|
||||
rgp, err := ps.rgpView.Get(entry.Key)
|
||||
if err != nil {
|
||||
return errwrap.Wrapf("failed looking up conflicting policy: {{err}}", err)
|
||||
}
|
||||
if rgp != nil {
|
||||
return fmt.Errorf("cannot reuse policy names between ACLs and RGPs")
|
||||
}
|
||||
if err := ps.aclView.Put(entry); err != nil {
|
||||
return errwrap.Wrapf("failed to persist policy: {{err}}", err)
|
||||
}
|
||||
ps.policyTypeMap.Store(p.Name, PolicyTypeACL)
|
||||
|
||||
if ps.tokenPoliciesLRU != nil {
|
||||
// Update the LRU cache
|
||||
ps.tokenPoliciesLRU.Add(p.Name, p)
|
||||
}
|
||||
|
||||
default:
|
||||
return fmt.Errorf("unknown policy type, cannot set")
|
||||
}
|
||||
|
||||
if ps.lru != nil {
|
||||
// Update the LRU cache
|
||||
ps.lru.Add(p.Name, p)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetPolicy is used to fetch the named policy
|
||||
func (ps *PolicyStore) GetPolicy(name string) (*Policy, error) {
|
||||
func (ps *PolicyStore) GetPolicy(name string, policyType PolicyType) (*Policy, error) {
|
||||
defer metrics.MeasureSince([]string{"policy", "get_policy"}, time.Now())
|
||||
|
||||
if ps.lru != nil {
|
||||
// Policies are normalized to lower-case
|
||||
name = ps.sanitizeName(name)
|
||||
|
||||
var cache *lru.TwoQueueCache
|
||||
var view *BarrierView
|
||||
switch policyType {
|
||||
case PolicyTypeACL:
|
||||
cache = ps.tokenPoliciesLRU
|
||||
view = ps.aclView
|
||||
case PolicyTypeToken:
|
||||
cache = ps.tokenPoliciesLRU
|
||||
val, ok := ps.policyTypeMap.Load(name)
|
||||
if !ok {
|
||||
// Doesn't exist
|
||||
return nil, nil
|
||||
}
|
||||
policyType = val.(PolicyType)
|
||||
switch policyType {
|
||||
case PolicyTypeACL:
|
||||
view = ps.aclView
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid type of policy in type map: %s", policyType)
|
||||
}
|
||||
}
|
||||
|
||||
if cache != nil {
|
||||
// Check for cached policy
|
||||
if raw, ok := ps.lru.Get(name); ok {
|
||||
if raw, ok := cache.Get(name); ok {
|
||||
return raw.(*Policy), nil
|
||||
}
|
||||
}
|
||||
|
||||
// Policies are normalized to lower-case
|
||||
name = strings.ToLower(strings.TrimSpace(name))
|
||||
|
||||
// Special case the root policy
|
||||
if name == "root" {
|
||||
if policyType == PolicyTypeACL && name == "root" {
|
||||
p := &Policy{Name: "root"}
|
||||
if ps.lru != nil {
|
||||
ps.lru.Add(p.Name, p)
|
||||
if cache != nil {
|
||||
cache.Add(p.Name, p)
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// Load the policy in
|
||||
out, err := ps.view.Get(name)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read policy: %v", err)
|
||||
ps.modifyLock.Lock()
|
||||
defer ps.modifyLock.Unlock()
|
||||
|
||||
// See if anything has added it since we got the lock
|
||||
if cache != nil {
|
||||
if raw, ok := cache.Get(name); ok {
|
||||
return raw.(*Policy), nil
|
||||
}
|
||||
}
|
||||
|
||||
out, err := view.Get(name)
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("failed to read policy: {{err}}", err)
|
||||
}
|
||||
|
||||
if out == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// In Vault 0.1.X we stored the raw policy, but in
|
||||
// Vault 0.2 we switch to the PolicyEntry
|
||||
policyEntry := new(PolicyEntry)
|
||||
var policy *Policy
|
||||
if err := out.DecodeJSON(policyEntry); err == nil {
|
||||
// Parse normally
|
||||
p, err := Parse(policyEntry.Raw)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse policy: %v", err)
|
||||
}
|
||||
p.Name = name
|
||||
policy = p
|
||||
policy := new(Policy)
|
||||
err = out.DecodeJSON(policyEntry)
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("failed to parse policy: {{err}}", err)
|
||||
}
|
||||
|
||||
// Set these up here so that they're available for loading into
|
||||
// Sentinel
|
||||
policy.Name = name
|
||||
policy.Raw = policyEntry.Raw
|
||||
policy.Type = policyEntry.Type
|
||||
switch policyEntry.Type {
|
||||
case PolicyTypeACL:
|
||||
// Parse normally
|
||||
p, err := ParseACLPolicy(policyEntry.Raw)
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("failed to parse policy: {{err}}", err)
|
||||
}
|
||||
policy.Paths = p.Paths
|
||||
// Reset this in case they set the name in the policy itself
|
||||
policy.Name = name
|
||||
|
||||
ps.policyTypeMap.Store(name, PolicyTypeACL)
|
||||
} else {
|
||||
// On error, attempt to use V1 parsing
|
||||
p, err := Parse(string(out.Value))
|
||||
|
@ -300,24 +396,34 @@ func (ps *PolicyStore) GetPolicy(name string) (*Policy, error) {
|
|||
for _, pp := range p.Paths {
|
||||
pp.Glob = true
|
||||
}
|
||||
policy = p
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown policy type %q", policyEntry.Type.String())
|
||||
}
|
||||
|
||||
if ps.lru != nil {
|
||||
if cache != nil {
|
||||
// Update the LRU cache
|
||||
ps.lru.Add(name, policy)
|
||||
cache.Add(name, policy)
|
||||
}
|
||||
|
||||
return policy, nil
|
||||
}
|
||||
|
||||
// ListPolicies is used to list the available policies
|
||||
func (ps *PolicyStore) ListPolicies() ([]string, error) {
|
||||
func (ps *PolicyStore) ListPolicies(policyType PolicyType) ([]string, error) {
|
||||
defer metrics.MeasureSince([]string{"policy", "list_policies"}, time.Now())
|
||||
// Scan the view, since the policy names are the same as the
|
||||
// key names.
|
||||
keys, err := logical.CollectKeys(ps.view)
|
||||
var keys []string
|
||||
var err error
|
||||
switch policyType {
|
||||
case PolicyTypeACL:
|
||||
keys, err = logical.CollectKeys(ps.aclView)
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown policy type %s", policyType)
|
||||
}
|
||||
|
||||
// We only have non-assignable ACL policies at the moment
|
||||
for _, nonAssignable := range nonAssignablePolicies {
|
||||
deleteIndex := -1
|
||||
//Find indices of non-assignable policies in keys
|
||||
|
@ -338,24 +444,36 @@ func (ps *PolicyStore) ListPolicies() ([]string, error) {
|
|||
}
|
||||
|
||||
// DeletePolicy is used to delete the named policy
|
||||
func (ps *PolicyStore) DeletePolicy(name string) error {
|
||||
func (ps *PolicyStore) DeletePolicy(name string, policyType PolicyType) error {
|
||||
defer metrics.MeasureSince([]string{"policy", "delete_policy"}, time.Now())
|
||||
|
||||
// Policies are normalized to lower-case
|
||||
name = strings.ToLower(strings.TrimSpace(name))
|
||||
if strutil.StrListContains(immutablePolicies, name) {
|
||||
return fmt.Errorf("cannot delete %s policy", name)
|
||||
}
|
||||
if name == "default" {
|
||||
return fmt.Errorf("cannot delete default policy")
|
||||
}
|
||||
if err := ps.view.Delete(name); err != nil {
|
||||
return fmt.Errorf("failed to delete policy: %v", err)
|
||||
}
|
||||
ps.modifyLock.Lock()
|
||||
defer ps.modifyLock.Unlock()
|
||||
|
||||
// Policies are normalized to lower-case
|
||||
name = ps.sanitizeName(name)
|
||||
|
||||
switch policyType {
|
||||
case PolicyTypeACL:
|
||||
if strutil.StrListContains(immutablePolicies, name) {
|
||||
return fmt.Errorf("cannot delete %s policy", name)
|
||||
}
|
||||
if name == "default" {
|
||||
return fmt.Errorf("cannot delete default policy")
|
||||
}
|
||||
|
||||
err := ps.aclView.Delete(name)
|
||||
if err != nil {
|
||||
return errwrap.Wrapf("failed to delete policy: {{err}}", err)
|
||||
}
|
||||
|
||||
if ps.tokenPoliciesLRU != nil {
|
||||
// Clear the cache
|
||||
ps.tokenPoliciesLRU.Remove(name)
|
||||
}
|
||||
|
||||
ps.policyTypeMap.Delete(name)
|
||||
|
||||
if ps.lru != nil {
|
||||
// Clear the cache
|
||||
ps.lru.Remove(name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -364,25 +482,25 @@ func (ps *PolicyStore) DeletePolicy(name string) error {
|
|||
// named policies.
|
||||
func (ps *PolicyStore) ACL(names ...string) (*ACL, error) {
|
||||
// Fetch the policies
|
||||
var policy []*Policy
|
||||
var policies []*Policy
|
||||
for _, name := range names {
|
||||
p, err := ps.GetPolicy(name)
|
||||
p, err := ps.GetPolicy(name, PolicyTypeToken)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get policy '%s': %v", name, err)
|
||||
return nil, errwrap.Wrapf("failed to get policy: {{err}}", err)
|
||||
}
|
||||
policy = append(policy, p)
|
||||
policies = append(policies, p)
|
||||
}
|
||||
|
||||
// Construct the ACL
|
||||
acl, err := NewACL(policy)
|
||||
acl, err := NewACL(policies)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to construct ACL: %v", err)
|
||||
return nil, errwrap.Wrapf("failed to construct ACL: {{err}}", err)
|
||||
}
|
||||
return acl, nil
|
||||
}
|
||||
|
||||
func (ps *PolicyStore) createDefaultPolicy() error {
|
||||
policy, err := Parse(defaultPolicy)
|
||||
policy, err := ParseACLPolicy(defaultPolicy)
|
||||
if err != nil {
|
||||
return errwrap.Wrapf("error parsing default policy: {{err}}", err)
|
||||
}
|
||||
|
@ -392,11 +510,12 @@ func (ps *PolicyStore) createDefaultPolicy() error {
|
|||
}
|
||||
|
||||
policy.Name = "default"
|
||||
policy.Type = PolicyTypeACL
|
||||
return ps.setPolicyInternal(policy)
|
||||
}
|
||||
|
||||
func (ps *PolicyStore) createResponseWrappingPolicy() error {
|
||||
policy, err := Parse(responseWrappingPolicy)
|
||||
policy, err := ParseACLPolicy(responseWrappingPolicy)
|
||||
if err != nil {
|
||||
return errwrap.Wrapf(fmt.Sprintf("error parsing %s policy: {{err}}", responseWrappingPolicyName), err)
|
||||
}
|
||||
|
@ -406,5 +525,10 @@ func (ps *PolicyStore) createResponseWrappingPolicy() error {
|
|||
}
|
||||
|
||||
policy.Name = responseWrappingPolicyName
|
||||
policy.Type = PolicyTypeACL
|
||||
return ps.setPolicyInternal(policy)
|
||||
}
|
||||
|
||||
func (ps *PolicyStore) sanitizeName(name string) string {
|
||||
return strings.ToLower(strings.TrimSpace(name))
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ func TestPolicyStore_Root(t *testing.T) {
|
|||
ps := mockPolicyStore(t)
|
||||
|
||||
// Get should return a special policy
|
||||
p, err := ps.GetPolicy("root")
|
||||
p, err := ps.GetPolicy("root", PolicyTypeToken)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ func TestPolicyStore_Root(t *testing.T) {
|
|||
}
|
||||
|
||||
// Delete should fail
|
||||
err = ps.DeletePolicy("root")
|
||||
err = ps.DeletePolicy("root", PolicyTypeACL)
|
||||
if err.Error() != "cannot delete root policy" {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ func TestPolicyStore_CRUD(t *testing.T) {
|
|||
|
||||
func testPolicyStore_CRUD(t *testing.T, ps *PolicyStore) {
|
||||
// Get should return nothing
|
||||
p, err := ps.GetPolicy("Dev")
|
||||
p, err := ps.GetPolicy("Dev", PolicyTypeToken)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
@ -70,13 +70,13 @@ func testPolicyStore_CRUD(t *testing.T, ps *PolicyStore) {
|
|||
}
|
||||
|
||||
// Delete should be no-op
|
||||
err = ps.DeletePolicy("deV")
|
||||
err = ps.DeletePolicy("deV", PolicyTypeACL)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
// List should be blank
|
||||
out, err := ps.ListPolicies()
|
||||
out, err := ps.ListPolicies(PolicyTypeACL)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
@ -85,14 +85,14 @@ func testPolicyStore_CRUD(t *testing.T, ps *PolicyStore) {
|
|||
}
|
||||
|
||||
// Set should work
|
||||
policy, _ := Parse(aclPolicy)
|
||||
policy, _ := ParseACLPolicy(aclPolicy)
|
||||
err = ps.SetPolicy(policy)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
// Get should work
|
||||
p, err = ps.GetPolicy("dEv")
|
||||
p, err = ps.GetPolicy("dEv", PolicyTypeToken)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ func testPolicyStore_CRUD(t *testing.T, ps *PolicyStore) {
|
|||
}
|
||||
|
||||
// List should be one element
|
||||
out, err = ps.ListPolicies()
|
||||
out, err = ps.ListPolicies(PolicyTypeACL)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
@ -110,13 +110,13 @@ func testPolicyStore_CRUD(t *testing.T, ps *PolicyStore) {
|
|||
}
|
||||
|
||||
// Delete should be clear the entry
|
||||
err = ps.DeletePolicy("Dev")
|
||||
err = ps.DeletePolicy("Dev", PolicyTypeACL)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
// Get should fail
|
||||
p, err = ps.GetPolicy("deV")
|
||||
p, err = ps.GetPolicy("deV", PolicyTypeToken)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
@ -134,7 +134,7 @@ func TestPolicyStore_Predefined(t *testing.T) {
|
|||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
// List should be two elements
|
||||
out, err := core.policyStore.ListPolicies()
|
||||
out, err := core.policyStore.ListPolicies(PolicyTypeACL)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
@ -143,17 +143,23 @@ func TestPolicyStore_Predefined(t *testing.T) {
|
|||
t.Fatalf("bad: %v", out)
|
||||
}
|
||||
|
||||
pCubby, err := core.policyStore.GetPolicy("response-wrapping")
|
||||
pCubby, err := core.policyStore.GetPolicy("response-wrapping", PolicyTypeToken)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
if pCubby == nil {
|
||||
t.Fatal("nil cubby policy")
|
||||
}
|
||||
if pCubby.Raw != responseWrappingPolicy {
|
||||
t.Fatalf("bad: expected\n%s\ngot\n%s\n", responseWrappingPolicy, pCubby.Raw)
|
||||
}
|
||||
pRoot, err := core.policyStore.GetPolicy("root")
|
||||
pRoot, err := core.policyStore.GetPolicy("root", PolicyTypeToken)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
if pRoot == nil {
|
||||
t.Fatal("nil root policy")
|
||||
}
|
||||
|
||||
err = core.policyStore.SetPolicy(pCubby)
|
||||
if err == nil {
|
||||
|
@ -163,11 +169,11 @@ func TestPolicyStore_Predefined(t *testing.T) {
|
|||
if err == nil {
|
||||
t.Fatalf("expected err setting %s", pRoot.Name)
|
||||
}
|
||||
err = core.policyStore.DeletePolicy(pCubby.Name)
|
||||
err = core.policyStore.DeletePolicy(pCubby.Name, PolicyTypeACL)
|
||||
if err == nil {
|
||||
t.Fatalf("expected err deleting %s", pCubby.Name)
|
||||
}
|
||||
err = core.policyStore.DeletePolicy(pRoot.Name)
|
||||
err = core.policyStore.DeletePolicy(pRoot.Name, PolicyTypeACL)
|
||||
if err == nil {
|
||||
t.Fatalf("expected err deleting %s", pRoot.Name)
|
||||
}
|
||||
|
@ -176,12 +182,12 @@ func TestPolicyStore_Predefined(t *testing.T) {
|
|||
func TestPolicyStore_ACL(t *testing.T) {
|
||||
ps := mockPolicyStore(t)
|
||||
|
||||
policy, _ := Parse(aclPolicy)
|
||||
policy, _ := ParseACLPolicy(aclPolicy)
|
||||
err := ps.SetPolicy(policy)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
policy, _ = Parse(aclPolicy2)
|
||||
policy, _ = ParseACLPolicy(aclPolicy2)
|
||||
err = ps.SetPolicy(policy)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
|
@ -193,26 +199,3 @@ func TestPolicyStore_ACL(t *testing.T) {
|
|||
}
|
||||
testLayeredACL(t, acl)
|
||||
}
|
||||
|
||||
func TestPolicyStore_v1Upgrade(t *testing.T) {
|
||||
ps := mockPolicyStore(t)
|
||||
|
||||
// Put a V1 record
|
||||
raw := `path "foo" { policy = "read" }`
|
||||
ps.view.Put(&logical.StorageEntry{Key: "old", Value: []byte(raw)})
|
||||
|
||||
// Do a read
|
||||
p, err := ps.GetPolicy("old")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
if p == nil || len(p.Paths) != 1 {
|
||||
t.Fatalf("bad policy: %#v", p)
|
||||
}
|
||||
|
||||
// Check that glob is enabled
|
||||
if !p.Paths[0].Glob {
|
||||
t.Fatalf("should enable glob")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -88,7 +88,7 @@ path "test/types" {
|
|||
`)
|
||||
|
||||
func TestPolicy_Parse(t *testing.T) {
|
||||
p, err := Parse(rawPolicy)
|
||||
p, err := ParseACLPolicy(rawPolicy)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
@ -97,17 +97,17 @@ func TestPolicy_Parse(t *testing.T) {
|
|||
t.Fatalf("bad name: %q", p.Name)
|
||||
}
|
||||
|
||||
expect := []*PathCapabilities{
|
||||
&PathCapabilities{
|
||||
expect := []*PathRules{
|
||||
&PathRules{
|
||||
Prefix: "",
|
||||
Policy: "deny",
|
||||
Capabilities: []string{
|
||||
"deny",
|
||||
},
|
||||
Permissions: &Permissions{CapabilitiesBitmap: DenyCapabilityInt},
|
||||
Permissions: &ACLPermissions{CapabilitiesBitmap: DenyCapabilityInt},
|
||||
Glob: true,
|
||||
},
|
||||
&PathCapabilities{
|
||||
&PathRules{
|
||||
Prefix: "stage/",
|
||||
Policy: "sudo",
|
||||
Capabilities: []string{
|
||||
|
@ -118,22 +118,22 @@ func TestPolicy_Parse(t *testing.T) {
|
|||
"list",
|
||||
"sudo",
|
||||
},
|
||||
Permissions: &Permissions{
|
||||
Permissions: &ACLPermissions{
|
||||
CapabilitiesBitmap: (CreateCapabilityInt | ReadCapabilityInt | UpdateCapabilityInt | DeleteCapabilityInt | ListCapabilityInt | SudoCapabilityInt),
|
||||
},
|
||||
Glob: true,
|
||||
},
|
||||
&PathCapabilities{
|
||||
&PathRules{
|
||||
Prefix: "prod/version",
|
||||
Policy: "read",
|
||||
Capabilities: []string{
|
||||
"read",
|
||||
"list",
|
||||
},
|
||||
Permissions: &Permissions{CapabilitiesBitmap: (ReadCapabilityInt | ListCapabilityInt)},
|
||||
Permissions: &ACLPermissions{CapabilitiesBitmap: (ReadCapabilityInt | ListCapabilityInt)},
|
||||
Glob: false,
|
||||
},
|
||||
&PathCapabilities{
|
||||
&PathRules{
|
||||
Prefix: "foo/bar",
|
||||
Policy: "read",
|
||||
Capabilities: []string{
|
||||
|
@ -142,14 +142,14 @@ func TestPolicy_Parse(t *testing.T) {
|
|||
},
|
||||
MinWrappingTTLHCL: 300,
|
||||
MaxWrappingTTLHCL: "1h",
|
||||
Permissions: &Permissions{
|
||||
Permissions: &ACLPermissions{
|
||||
CapabilitiesBitmap: (ReadCapabilityInt | ListCapabilityInt),
|
||||
MinWrappingTTL: 300 * time.Second,
|
||||
MaxWrappingTTL: 3600 * time.Second,
|
||||
},
|
||||
Glob: false,
|
||||
},
|
||||
&PathCapabilities{
|
||||
&PathRules{
|
||||
Prefix: "foo/bar",
|
||||
Policy: "",
|
||||
Capabilities: []string{
|
||||
|
@ -158,14 +158,14 @@ func TestPolicy_Parse(t *testing.T) {
|
|||
},
|
||||
MinWrappingTTLHCL: "300s",
|
||||
MaxWrappingTTLHCL: 3600,
|
||||
Permissions: &Permissions{
|
||||
Permissions: &ACLPermissions{
|
||||
CapabilitiesBitmap: (CreateCapabilityInt | SudoCapabilityInt),
|
||||
MinWrappingTTL: 300 * time.Second,
|
||||
MaxWrappingTTL: 3600 * time.Second,
|
||||
},
|
||||
Glob: false,
|
||||
},
|
||||
&PathCapabilities{
|
||||
&PathRules{
|
||||
Prefix: "foo/bar",
|
||||
Policy: "",
|
||||
Capabilities: []string{
|
||||
|
@ -173,13 +173,13 @@ func TestPolicy_Parse(t *testing.T) {
|
|||
"sudo",
|
||||
},
|
||||
AllowedParametersHCL: map[string][]interface{}{"zip": {}, "zap": {}},
|
||||
Permissions: &Permissions{
|
||||
Permissions: &ACLPermissions{
|
||||
CapabilitiesBitmap: (CreateCapabilityInt | SudoCapabilityInt),
|
||||
AllowedParameters: map[string][]interface{}{"zip": {}, "zap": {}},
|
||||
},
|
||||
Glob: false,
|
||||
},
|
||||
&PathCapabilities{
|
||||
&PathRules{
|
||||
Prefix: "baz/bar",
|
||||
Policy: "",
|
||||
Capabilities: []string{
|
||||
|
@ -187,13 +187,13 @@ func TestPolicy_Parse(t *testing.T) {
|
|||
"sudo",
|
||||
},
|
||||
DeniedParametersHCL: map[string][]interface{}{"zip": []interface{}{}, "zap": []interface{}{}},
|
||||
Permissions: &Permissions{
|
||||
Permissions: &ACLPermissions{
|
||||
CapabilitiesBitmap: (CreateCapabilityInt | SudoCapabilityInt),
|
||||
DeniedParameters: map[string][]interface{}{"zip": []interface{}{}, "zap": []interface{}{}},
|
||||
},
|
||||
Glob: false,
|
||||
},
|
||||
&PathCapabilities{
|
||||
&PathRules{
|
||||
Prefix: "biz/bar",
|
||||
Policy: "",
|
||||
Capabilities: []string{
|
||||
|
@ -202,14 +202,14 @@ func TestPolicy_Parse(t *testing.T) {
|
|||
},
|
||||
AllowedParametersHCL: map[string][]interface{}{"zim": {}, "zam": {}},
|
||||
DeniedParametersHCL: map[string][]interface{}{"zip": {}, "zap": {}},
|
||||
Permissions: &Permissions{
|
||||
Permissions: &ACLPermissions{
|
||||
CapabilitiesBitmap: (CreateCapabilityInt | SudoCapabilityInt),
|
||||
AllowedParameters: map[string][]interface{}{"zim": {}, "zam": {}},
|
||||
DeniedParameters: map[string][]interface{}{"zip": {}, "zap": {}},
|
||||
},
|
||||
Glob: false,
|
||||
},
|
||||
&PathCapabilities{
|
||||
&PathRules{
|
||||
Prefix: "test/types",
|
||||
Policy: "",
|
||||
Capabilities: []string{
|
||||
|
@ -218,7 +218,7 @@ func TestPolicy_Parse(t *testing.T) {
|
|||
},
|
||||
AllowedParametersHCL: map[string][]interface{}{"map": []interface{}{map[string]interface{}{"good": "one"}}, "int": []interface{}{1, 2}},
|
||||
DeniedParametersHCL: map[string][]interface{}{"string": []interface{}{"test"}, "bool": []interface{}{false}},
|
||||
Permissions: &Permissions{
|
||||
Permissions: &ACLPermissions{
|
||||
CapabilitiesBitmap: (CreateCapabilityInt | SudoCapabilityInt),
|
||||
AllowedParameters: map[string][]interface{}{"map": []interface{}{map[string]interface{}{"good": "one"}}, "int": []interface{}{1, 2}},
|
||||
DeniedParameters: map[string][]interface{}{"string": []interface{}{"test"}, "bool": []interface{}{false}},
|
||||
|
@ -232,7 +232,7 @@ func TestPolicy_Parse(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestPolicy_ParseBadRoot(t *testing.T) {
|
||||
_, err := Parse(strings.TrimSpace(`
|
||||
_, err := ParseACLPolicy(strings.TrimSpace(`
|
||||
name = "test"
|
||||
bad = "foo"
|
||||
nope = "yes"
|
||||
|
@ -251,7 +251,7 @@ nope = "yes"
|
|||
}
|
||||
|
||||
func TestPolicy_ParseBadPath(t *testing.T) {
|
||||
_, err := Parse(strings.TrimSpace(`
|
||||
_, err := ParseACLPolicy(strings.TrimSpace(`
|
||||
path "/" {
|
||||
capabilities = ["read"]
|
||||
capabilites = ["read"]
|
||||
|
@ -267,7 +267,7 @@ path "/" {
|
|||
}
|
||||
|
||||
func TestPolicy_ParseBadPolicy(t *testing.T) {
|
||||
_, err := Parse(strings.TrimSpace(`
|
||||
_, err := ParseACLPolicy(strings.TrimSpace(`
|
||||
path "/" {
|
||||
policy = "banana"
|
||||
}
|
||||
|
@ -282,7 +282,7 @@ path "/" {
|
|||
}
|
||||
|
||||
func TestPolicy_ParseBadWrapping(t *testing.T) {
|
||||
_, err := Parse(strings.TrimSpace(`
|
||||
_, err := ParseACLPolicy(strings.TrimSpace(`
|
||||
path "/" {
|
||||
policy = "read"
|
||||
min_wrapping_ttl = 400
|
||||
|
@ -299,7 +299,7 @@ path "/" {
|
|||
}
|
||||
|
||||
func TestPolicy_ParseBadCapabilities(t *testing.T) {
|
||||
_, err := Parse(strings.TrimSpace(`
|
||||
_, err := ParseACLPolicy(strings.TrimSpace(`
|
||||
path "/" {
|
||||
capabilities = ["read", "banana"]
|
||||
}
|
||||
|
|
|
@ -41,6 +41,11 @@ type RekeyBackup struct {
|
|||
Keys map[string][]string
|
||||
}
|
||||
|
||||
// RekeyThreshold returns the secret threshold for the current seal
|
||||
// config. This threshold can either be the barrier key threshold or
|
||||
// the recovery key threshold, depending on whether rekey is being
|
||||
// performed on the recovery key, or whether the seal supports
|
||||
// recovery keys.
|
||||
func (c *Core) RekeyThreshold(recovery bool) (int, error) {
|
||||
c.stateLock.RLock()
|
||||
defer c.stateLock.RUnlock()
|
||||
|
@ -56,7 +61,10 @@ func (c *Core) RekeyThreshold(recovery bool) (int, error) {
|
|||
|
||||
var config *SealConfig
|
||||
var err error
|
||||
if recovery {
|
||||
// If we are rekeying the recovery key, or if the seal supports
|
||||
// recovery keys and we are rekeying the barrier key, we use the
|
||||
// recovery config as the threshold instead.
|
||||
if recovery || c.seal.RecoveryKeySupported() {
|
||||
config, err = c.seal.RecoveryConfig()
|
||||
} else {
|
||||
config, err = c.seal.BarrierConfig()
|
||||
|
@ -68,7 +76,7 @@ func (c *Core) RekeyThreshold(recovery bool) (int, error) {
|
|||
return config.SecretThreshold, nil
|
||||
}
|
||||
|
||||
// RekeyProgress is used to return the rekey progress (num shares)
|
||||
// RekeyProgress is used to return the rekey progress (num shares).
|
||||
func (c *Core) RekeyProgress(recovery bool) (int, error) {
|
||||
c.stateLock.RLock()
|
||||
defer c.stateLock.RUnlock()
|
||||
|
@ -117,6 +125,8 @@ func (c *Core) RekeyConfig(recovery bool) (*SealConfig, error) {
|
|||
return conf, nil
|
||||
}
|
||||
|
||||
// RekeyInit will either initialize the rekey of barrier or recovery key.
|
||||
// recovery determines whether this is a rekey on the barrier or recovery key.
|
||||
func (c *Core) RekeyInit(config *SealConfig, recovery bool) error {
|
||||
if recovery {
|
||||
return c.RecoveryRekeyInit(config)
|
||||
|
@ -138,6 +148,10 @@ func (c *Core) BarrierRekeyInit(config *SealConfig) error {
|
|||
}
|
||||
}
|
||||
|
||||
if c.seal.RecoveryKeySupported() && c.seal.RecoveryType() == config.Type {
|
||||
c.logger.Debug("core: using recovery seal configuration to rekey barrier key")
|
||||
}
|
||||
|
||||
// Check if the seal configuration is valid
|
||||
if err := config.Validate(); err != nil {
|
||||
c.logger.Error("core: invalid rekey seal configuration", "error", err)
|
||||
|
@ -228,6 +242,7 @@ func (c *Core) RecoveryRekeyInit(config *SealConfig) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// RekeyUpdate is used to provide a new key part for the barrier or recovery key.
|
||||
func (c *Core) RekeyUpdate(key []byte, nonce string, recovery bool) (*RekeyResult, error) {
|
||||
if recovery {
|
||||
return c.RecoveryRekeyUpdate(key, nonce)
|
||||
|
@ -235,7 +250,11 @@ func (c *Core) RekeyUpdate(key []byte, nonce string, recovery bool) (*RekeyResul
|
|||
return c.BarrierRekeyUpdate(key, nonce)
|
||||
}
|
||||
|
||||
// BarrierRekeyUpdate is used to provide a new key part
|
||||
// BarrierRekeyUpdate is used to provide a new key part. Barrier rekey can be done
|
||||
// with unseal keys, or recovery keys if that's supported and we are storing the barrier
|
||||
// key.
|
||||
//
|
||||
// N.B.: If recovery keys are used to rekey, the new barrier key shares are not returned.
|
||||
func (c *Core) BarrierRekeyUpdate(key []byte, nonce string) (*RekeyResult, error) {
|
||||
// Ensure we are already unsealed
|
||||
c.stateLock.RLock()
|
||||
|
@ -261,7 +280,15 @@ func (c *Core) BarrierRekeyUpdate(key []byte, nonce string) (*RekeyResult, error
|
|||
defer c.rekeyLock.Unlock()
|
||||
|
||||
// Get the seal configuration
|
||||
existingConfig, err := c.seal.BarrierConfig()
|
||||
var existingConfig *SealConfig
|
||||
var err error
|
||||
var useRecovery bool // Determines whether recovery key is being used to rekey the master key
|
||||
if c.seal.StoredKeysSupported() && c.seal.RecoveryKeySupported() {
|
||||
existingConfig, err = c.seal.RecoveryConfig()
|
||||
useRecovery = true
|
||||
} else {
|
||||
existingConfig, err = c.seal.BarrierConfig()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -298,22 +325,29 @@ func (c *Core) BarrierRekeyUpdate(key []byte, nonce string) (*RekeyResult, error
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
// Recover the master key
|
||||
var masterKey []byte
|
||||
// Recover the master key or recovery key
|
||||
var recoveredKey []byte
|
||||
if existingConfig.SecretThreshold == 1 {
|
||||
masterKey = c.barrierRekeyProgress[0]
|
||||
recoveredKey = c.barrierRekeyProgress[0]
|
||||
c.barrierRekeyProgress = nil
|
||||
} else {
|
||||
masterKey, err = shamir.Combine(c.barrierRekeyProgress)
|
||||
recoveredKey, err = shamir.Combine(c.barrierRekeyProgress)
|
||||
c.barrierRekeyProgress = nil
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to compute master key: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := c.barrier.VerifyMaster(masterKey); err != nil {
|
||||
c.logger.Error("core: rekey aborted, master key verification failed", "error", err)
|
||||
return nil, err
|
||||
if useRecovery {
|
||||
if err := c.seal.VerifyRecoveryKey(recoveredKey); err != nil {
|
||||
c.logger.Error("core: rekey aborted, recovery key verification failed", "error", err)
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
if err := c.barrier.VerifyMaster(recoveredKey); err != nil {
|
||||
c.logger.Error("core: rekey aborted, master key verification failed", "error", err)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Generate a new master key
|
||||
|
@ -323,11 +357,11 @@ func (c *Core) BarrierRekeyUpdate(key []byte, nonce string) (*RekeyResult, error
|
|||
return nil, fmt.Errorf("master key generation failed: %v", err)
|
||||
}
|
||||
|
||||
// Return the master key if only a single key part is used
|
||||
results := &RekeyResult{
|
||||
Backup: c.barrierRekeyConfig.Backup,
|
||||
}
|
||||
|
||||
// Set result.SecretShares to the master key if only a single key
|
||||
// part is used -- no Shamir split required.
|
||||
if c.barrierRekeyConfig.SecretShares == 1 {
|
||||
results.SecretShares = append(results.SecretShares, newMasterKey)
|
||||
} else {
|
||||
|
@ -343,13 +377,14 @@ func (c *Core) BarrierRekeyUpdate(key []byte, nonce string) (*RekeyResult, error
|
|||
// If we are storing any shares, add them to the shares to store and remove
|
||||
// from the returned keys
|
||||
var keysToStore [][]byte
|
||||
if c.barrierRekeyConfig.StoredShares > 0 {
|
||||
if c.seal.StoredKeysSupported() && c.barrierRekeyConfig.StoredShares > 0 {
|
||||
for i := 0; i < c.barrierRekeyConfig.StoredShares; i++ {
|
||||
keysToStore = append(keysToStore, results.SecretShares[0])
|
||||
results.SecretShares = results.SecretShares[1:]
|
||||
}
|
||||
}
|
||||
|
||||
// If PGP keys are passed in, encrypt shares with corresponding PGP keys.
|
||||
if len(c.barrierRekeyConfig.PGPKeys) > 0 {
|
||||
hexEncodedShares := make([][]byte, len(results.SecretShares))
|
||||
for i, _ := range results.SecretShares {
|
||||
|
@ -360,6 +395,7 @@ func (c *Core) BarrierRekeyUpdate(key []byte, nonce string) (*RekeyResult, error
|
|||
return nil, err
|
||||
}
|
||||
|
||||
// If backup is enabled, store backup info in vault.coreBarrierUnsealKeysBackupPath
|
||||
if c.barrierRekeyConfig.Backup {
|
||||
backupInfo := map[string][]string{}
|
||||
for i := 0; i < len(results.PGPFingerprints); i++ {
|
||||
|
@ -453,21 +489,16 @@ func (c *Core) RecoveryRekeyUpdate(key []byte, nonce string) (*RekeyResult, erro
|
|||
defer c.rekeyLock.Unlock()
|
||||
|
||||
// Get the seal configuration
|
||||
barrierConfig, err := c.seal.BarrierConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Ensure the barrier is initialized
|
||||
if barrierConfig == nil {
|
||||
return nil, ErrNotInit
|
||||
}
|
||||
|
||||
existingConfig, err := c.seal.RecoveryConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Ensure the seal is initialized
|
||||
if existingConfig == nil {
|
||||
return nil, ErrNotInit
|
||||
}
|
||||
|
||||
// Ensure a rekey is in progress
|
||||
if c.recoveryRekeyConfig == nil {
|
||||
return nil, fmt.Errorf("no rekey in progress")
|
||||
|
@ -496,12 +527,12 @@ func (c *Core) RecoveryRekeyUpdate(key []byte, nonce string) (*RekeyResult, erro
|
|||
}
|
||||
|
||||
// Recover the master key
|
||||
var masterKey []byte
|
||||
var recoveryKey []byte
|
||||
if existingConfig.SecretThreshold == 1 {
|
||||
masterKey = c.recoveryRekeyProgress[0]
|
||||
recoveryKey = c.recoveryRekeyProgress[0]
|
||||
c.recoveryRekeyProgress = nil
|
||||
} else {
|
||||
masterKey, err = shamir.Combine(c.recoveryRekeyProgress)
|
||||
recoveryKey, err = shamir.Combine(c.recoveryRekeyProgress)
|
||||
c.recoveryRekeyProgress = nil
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to compute recovery key: %v", err)
|
||||
|
@ -509,7 +540,7 @@ func (c *Core) RecoveryRekeyUpdate(key []byte, nonce string) (*RekeyResult, erro
|
|||
}
|
||||
|
||||
// Verify the recovery key
|
||||
if err := c.seal.VerifyRecoveryKey(masterKey); err != nil {
|
||||
if err := c.seal.VerifyRecoveryKey(recoveryKey); err != nil {
|
||||
c.logger.Error("core: rekey aborted, recovery key verification failed", "error", err)
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -168,7 +168,7 @@ func testCore_Rekey_Update_Common(t *testing.T, c *Core, keys [][]byte, root str
|
|||
t.Fatalf("bad: no rekey config received")
|
||||
}
|
||||
|
||||
// Provide the master
|
||||
// Provide the master/recovery keys
|
||||
var result *RekeyResult
|
||||
for _, key := range keys {
|
||||
result, err = c.RekeyUpdate(key, rkconf.Nonce, recovery)
|
||||
|
@ -180,7 +180,7 @@ func testCore_Rekey_Update_Common(t *testing.T, c *Core, keys [][]byte, root str
|
|||
}
|
||||
}
|
||||
if result == nil || len(result.SecretShares) != newConf.SecretShares {
|
||||
t.Fatalf("Bad: %#v", result)
|
||||
t.Fatalf("rekey update error: %#v", result)
|
||||
}
|
||||
|
||||
// Should be no progress
|
||||
|
@ -189,16 +189,16 @@ func testCore_Rekey_Update_Common(t *testing.T, c *Core, keys [][]byte, root str
|
|||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
if num != 0 {
|
||||
t.Fatalf("bad: %d", num)
|
||||
t.Fatalf("rekey progress error: %d", num)
|
||||
}
|
||||
|
||||
// Should be no config
|
||||
conf, err := c.RekeyConfig(recovery)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
t.Fatalf("rekey config error: %v", err)
|
||||
}
|
||||
if conf != nil {
|
||||
t.Fatalf("bad: %v", conf)
|
||||
t.Fatalf("rekey config should be nil, got: %v", conf)
|
||||
}
|
||||
|
||||
// SealConfig should update
|
||||
|
@ -209,7 +209,7 @@ func testCore_Rekey_Update_Common(t *testing.T, c *Core, keys [][]byte, root str
|
|||
sealConf, err = c.seal.BarrierConfig()
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
t.Fatalf("seal config retrieval error: %v", err)
|
||||
}
|
||||
if sealConf == nil {
|
||||
t.Fatal("seal configuration is nil")
|
||||
|
@ -226,7 +226,7 @@ func testCore_Rekey_Update_Common(t *testing.T, c *Core, keys [][]byte, root str
|
|||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
for i := 0; i < 3; i++ {
|
||||
for i := 0; i < newConf.SecretThreshold; i++ {
|
||||
_, err = TestCoreUnseal(c, TestKeyCopy(result.SecretShares[i]))
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
|
@ -238,6 +238,13 @@ func testCore_Rekey_Update_Common(t *testing.T, c *Core, keys [][]byte, root str
|
|||
}
|
||||
|
||||
// Start another rekey, this time we require a quorum!
|
||||
// Skip this step if we are rekeying the barrier key with
|
||||
// recovery keys, since a new rekey should still be using
|
||||
// the same set of recovery keys.
|
||||
if !recovery && c.seal.RecoveryKeySupported() {
|
||||
return
|
||||
}
|
||||
|
||||
newConf = &SealConfig{
|
||||
Type: expType,
|
||||
SecretThreshold: 1,
|
||||
|
|
|
@ -152,9 +152,11 @@ func (c *Core) startForwarding() error {
|
|||
}
|
||||
|
||||
c.logger.Trace("core: got request forwarding connection")
|
||||
c.clusterParamsLock.RLock()
|
||||
go fws.ServeConn(conn, &http2.ServeConnOpts{
|
||||
Handler: c.rpcServer,
|
||||
})
|
||||
c.clusterParamsLock.RUnlock()
|
||||
|
||||
default:
|
||||
c.logger.Debug("core: unknown negotiated protocol on cluster port")
|
||||
|
|
|
@ -1,16 +1,6 @@
|
|||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// source: request_forwarding_service.proto
|
||||
|
||||
/*
|
||||
Package vault is a generated protocol buffer package.
|
||||
|
||||
It is generated from these files:
|
||||
request_forwarding_service.proto
|
||||
|
||||
It has these top-level messages:
|
||||
EchoRequest
|
||||
EchoReply
|
||||
*/
|
||||
package vault
|
||||
|
||||
import proto "github.com/golang/protobuf/proto"
|
||||
|
@ -28,21 +18,20 @@ var _ = proto.Marshal
|
|||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
|
||||
|
||||
type EchoRequest struct {
|
||||
Message string `protobuf:"bytes,1,opt,name=message" json:"message,omitempty"`
|
||||
Message string `protobuf:"bytes,1,opt,name=message" json:"message,omitempty"`
|
||||
// ClusterAddr is used to send up a standby node's address to the active
|
||||
// node upon heartbeat
|
||||
ClusterAddr string `protobuf:"bytes,2,opt,name=cluster_addr,json=clusterAddr" json:"cluster_addr,omitempty"`
|
||||
// ClusterAddrs is used to send up a list of cluster addresses to a dr
|
||||
// primary from a dr secondary
|
||||
ClusterAddrs []string `protobuf:"bytes,3,rep,name=cluster_addrs,json=clusterAddrs" json:"cluster_addrs,omitempty"`
|
||||
}
|
||||
|
||||
func (m *EchoRequest) Reset() { *m = EchoRequest{} }
|
||||
func (m *EchoRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*EchoRequest) ProtoMessage() {}
|
||||
func (*EchoRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
|
||||
func (*EchoRequest) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{0} }
|
||||
|
||||
func (m *EchoRequest) GetMessage() string {
|
||||
if m != nil {
|
||||
|
@ -58,6 +47,13 @@ func (m *EchoRequest) GetClusterAddr() string {
|
|||
return ""
|
||||
}
|
||||
|
||||
func (m *EchoRequest) GetClusterAddrs() []string {
|
||||
if m != nil {
|
||||
return m.ClusterAddrs
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type EchoReply struct {
|
||||
Message string `protobuf:"bytes,1,opt,name=message" json:"message,omitempty"`
|
||||
ClusterAddrs []string `protobuf:"bytes,2,rep,name=cluster_addrs,json=clusterAddrs" json:"cluster_addrs,omitempty"`
|
||||
|
@ -66,7 +62,7 @@ type EchoReply struct {
|
|||
func (m *EchoReply) Reset() { *m = EchoReply{} }
|
||||
func (m *EchoReply) String() string { return proto.CompactTextString(m) }
|
||||
func (*EchoReply) ProtoMessage() {}
|
||||
func (*EchoReply) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
|
||||
func (*EchoReply) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{1} }
|
||||
|
||||
func (m *EchoReply) GetMessage() string {
|
||||
if m != nil {
|
||||
|
@ -192,24 +188,25 @@ var _RequestForwarding_serviceDesc = grpc.ServiceDesc{
|
|||
Metadata: "request_forwarding_service.proto",
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("request_forwarding_service.proto", fileDescriptor0) }
|
||||
func init() { proto.RegisterFile("request_forwarding_service.proto", fileDescriptor1) }
|
||||
|
||||
var fileDescriptor0 = []byte{
|
||||
// 254 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x90, 0x3d, 0x4f, 0xc3, 0x30,
|
||||
0x10, 0x86, 0xdb, 0xf2, 0xa5, 0xb8, 0x05, 0x81, 0x61, 0x88, 0x32, 0x85, 0xb0, 0x74, 0x72, 0x24,
|
||||
0x58, 0x58, 0x18, 0x18, 0x60, 0xe8, 0x98, 0x3f, 0x10, 0xb9, 0xf6, 0x11, 0x47, 0x72, 0x6b, 0x73,
|
||||
0xe7, 0x14, 0x65, 0xe5, 0x97, 0x23, 0x92, 0x94, 0xa6, 0x0b, 0xe3, 0xbd, 0x27, 0x3d, 0xf7, 0xdc,
|
||||
0xcb, 0x52, 0x84, 0xcf, 0x06, 0x28, 0x94, 0x1f, 0x0e, 0xbf, 0x24, 0xea, 0x7a, 0x5b, 0x95, 0x04,
|
||||
0xb8, 0xab, 0x15, 0x08, 0x8f, 0x2e, 0x38, 0x7e, 0xb6, 0x93, 0x8d, 0x0d, 0xc9, 0x73, 0x55, 0x07,
|
||||
0xd3, 0xac, 0x85, 0x72, 0x9b, 0xdc, 0x48, 0x32, 0xb5, 0x72, 0xe8, 0xf3, 0x6e, 0x97, 0x1b, 0xb0,
|
||||
0x1e, 0x30, 0x3f, 0x20, 0xf2, 0xd0, 0x7a, 0xa0, 0x1e, 0x90, 0xad, 0xd8, 0xfc, 0x4d, 0x19, 0x57,
|
||||
0xf4, 0x87, 0x78, 0xcc, 0x2e, 0x36, 0x40, 0x24, 0x2b, 0x88, 0xa7, 0xe9, 0x74, 0x19, 0x15, 0xfb,
|
||||
0x91, 0xdf, 0xb3, 0x85, 0xb2, 0x0d, 0x05, 0xc0, 0x52, 0x6a, 0x8d, 0xf1, 0xac, 0x5b, 0xcf, 0x87,
|
||||
0xec, 0x55, 0x6b, 0xcc, 0x56, 0x2c, 0xea, 0x59, 0xde, 0xb6, 0xff, 0x90, 0x1e, 0xd8, 0xe5, 0x98,
|
||||
0x44, 0xf1, 0x2c, 0x3d, 0x59, 0x46, 0xc5, 0x62, 0x84, 0xa2, 0xc7, 0xef, 0x29, 0xbb, 0x19, 0xa4,
|
||||
0xde, 0xff, 0xcc, 0xf9, 0x0b, 0xbb, 0x1a, 0xa6, 0xbd, 0xf0, 0xad, 0x38, 0x3c, 0x26, 0x86, 0x30,
|
||||
0xb9, 0x3b, 0x0e, 0xc9, 0xbb, 0x2d, 0x41, 0x36, 0xe1, 0x82, 0x9d, 0xfe, 0x0a, 0x72, 0x2e, 0xba,
|
||||
0x6a, 0xc4, 0xe8, 0xf3, 0xe4, 0xfa, 0x28, 0xf3, 0xb6, 0xcd, 0x26, 0xeb, 0xf3, 0xae, 0xa3, 0xa7,
|
||||
0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x13, 0x7f, 0xc2, 0x88, 0x01, 0x00, 0x00,
|
||||
var fileDescriptor1 = []byte{
|
||||
// 261 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x90, 0x3f, 0x4f, 0xc3, 0x30,
|
||||
0x10, 0xc5, 0x9b, 0x96, 0x3f, 0x8a, 0x5b, 0x10, 0x18, 0x86, 0x28, 0x53, 0x08, 0x4b, 0x27, 0x47,
|
||||
0x82, 0x85, 0x85, 0x81, 0x01, 0x06, 0xc6, 0x7c, 0x81, 0x28, 0xb5, 0x8f, 0x38, 0x92, 0x5b, 0x9b,
|
||||
0x3b, 0xa7, 0x28, 0x2b, 0x9f, 0x1c, 0x91, 0xa4, 0x34, 0x55, 0x25, 0xc6, 0x7b, 0x77, 0xfa, 0xbd,
|
||||
0x7b, 0x8f, 0x25, 0x08, 0x9f, 0x0d, 0x90, 0x2f, 0x3e, 0x2c, 0x7e, 0x95, 0xa8, 0xea, 0x4d, 0x55,
|
||||
0x10, 0xe0, 0xb6, 0x96, 0x20, 0x1c, 0x5a, 0x6f, 0xf9, 0xe9, 0xb6, 0x6c, 0x8c, 0x8f, 0x9f, 0xaa,
|
||||
0xda, 0xeb, 0x66, 0x25, 0xa4, 0x5d, 0x67, 0xba, 0x24, 0x5d, 0x4b, 0x8b, 0x2e, 0xeb, 0x76, 0x99,
|
||||
0x06, 0xe3, 0x00, 0xb3, 0x3d, 0x22, 0xf3, 0xad, 0x03, 0xea, 0x01, 0xa9, 0x65, 0xf3, 0x57, 0xa9,
|
||||
0x6d, 0xde, 0x1b, 0xf1, 0x88, 0x9d, 0xaf, 0x81, 0xa8, 0xac, 0x20, 0x0a, 0x92, 0x60, 0x19, 0xe6,
|
||||
0xbb, 0x91, 0xdf, 0xb1, 0x85, 0x34, 0x0d, 0x79, 0xc0, 0xa2, 0x54, 0x0a, 0xa3, 0x69, 0xb7, 0x9e,
|
||||
0x0f, 0xda, 0x8b, 0x52, 0xc8, 0xef, 0xd9, 0xc5, 0xf8, 0x84, 0xa2, 0x59, 0x32, 0x5b, 0x86, 0xf9,
|
||||
0x62, 0x74, 0x43, 0xe9, 0x3b, 0x0b, 0x7b, 0x43, 0x67, 0xda, 0x7f, 0xec, 0x8e, 0x58, 0xd3, 0x63,
|
||||
0xd6, 0xc3, 0x77, 0xc0, 0xae, 0x87, 0xcf, 0xdf, 0xfe, 0xe2, 0xf1, 0x67, 0x76, 0x39, 0x4c, 0xbb,
|
||||
0x54, 0x37, 0x62, 0x9f, 0x5e, 0x0c, 0x62, 0x7c, 0x7b, 0x28, 0x92, 0xb3, 0x1b, 0x82, 0x74, 0xc2,
|
||||
0x05, 0x3b, 0xf9, 0x7d, 0x90, 0x73, 0xd1, 0xf5, 0x27, 0x46, 0xf5, 0xc4, 0x57, 0x07, 0x9a, 0x33,
|
||||
0x6d, 0x3a, 0x59, 0x9d, 0x75, 0x45, 0x3e, 0xfe, 0x04, 0x00, 0x00, 0xff, 0xff, 0xc0, 0xa1, 0xca,
|
||||
0xfe, 0xad, 0x01, 0x00, 0x00,
|
||||
}
|
||||
|
|
|
@ -6,7 +6,12 @@ package vault;
|
|||
|
||||
message EchoRequest {
|
||||
string message = 1;
|
||||
// ClusterAddr is used to send up a standby node's address to the active
|
||||
// node upon heartbeat
|
||||
string cluster_addr = 2;
|
||||
// ClusterAddrs is used to send up a list of cluster addresses to a dr
|
||||
// primary from a dr secondary
|
||||
repeated string cluster_addrs = 3;
|
||||
}
|
||||
|
||||
message EchoReply {
|
||||
|
|
|
@ -16,6 +16,10 @@ import (
|
|||
"github.com/hashicorp/vault/logical"
|
||||
)
|
||||
|
||||
const (
|
||||
replTimeout = 10 * time.Second
|
||||
)
|
||||
|
||||
// HandleRequest is used to handle a new incoming request
|
||||
func (c *Core) HandleRequest(req *logical.Request) (resp *logical.Response, err error) {
|
||||
c.stateLock.RLock()
|
||||
|
@ -117,7 +121,7 @@ func (c *Core) handleRequest(req *logical.Request) (retResp *logical.Response, r
|
|||
defer metrics.MeasureSince([]string{"core", "handle_request"}, time.Now())
|
||||
|
||||
// Validate the token
|
||||
auth, te, ctErr := c.checkToken(req)
|
||||
auth, te, ctErr := c.checkToken(req, false)
|
||||
// We run this logic first because we want to decrement the use count even in the case of an error
|
||||
if te != nil {
|
||||
// Attempt to use the token (decrement NumUses)
|
||||
|
@ -323,11 +327,16 @@ func (c *Core) handleRequest(req *logical.Request) (retResp *logical.Response, r
|
|||
|
||||
// handleLoginRequest is used to handle a login request, which is an
|
||||
// unauthenticated request to the backend.
|
||||
func (c *Core) handleLoginRequest(req *logical.Request) (*logical.Response, *logical.Auth, error) {
|
||||
func (c *Core) handleLoginRequest(req *logical.Request) (retResp *logical.Response, retAuth *logical.Auth, retErr error) {
|
||||
defer metrics.MeasureSince([]string{"core", "handle_login_request"}, time.Now())
|
||||
|
||||
req.Unauthenticated = true
|
||||
|
||||
var auth *logical.Auth
|
||||
// Create an audit trail of the request, auth is not available on login requests
|
||||
if err := c.auditBroker.LogRequest(nil, req, c.auditedHeaders, nil); err != nil {
|
||||
// Create an audit trail of the request. Attach auth if it was returned,
|
||||
// e.g. if a token was provided.
|
||||
if err := c.auditBroker.LogRequest(auth, req, c.auditedHeaders, nil); err != nil {
|
||||
c.logger.Error("core: failed to audit request", "path", req.Path, "error", err)
|
||||
return nil, nil, ErrInternalError
|
||||
}
|
||||
|
@ -386,7 +395,6 @@ func (c *Core) handleLoginRequest(req *logical.Request) (*logical.Response, *log
|
|||
}
|
||||
|
||||
// If the response generated an authentication, then generate the token
|
||||
var auth *logical.Auth
|
||||
if resp != nil && resp.Auth != nil {
|
||||
var entity *identity.Entity
|
||||
auth = resp.Auth
|
||||
|
|
|
@ -39,12 +39,13 @@ func NewRouter() *Router {
|
|||
|
||||
// routeEntry is used to represent a mount point in the router
|
||||
type routeEntry struct {
|
||||
tainted bool
|
||||
backend logical.Backend
|
||||
mountEntry *MountEntry
|
||||
storageView *BarrierView
|
||||
rootPaths *radix.Tree
|
||||
loginPaths *radix.Tree
|
||||
tainted bool
|
||||
backend logical.Backend
|
||||
mountEntry *MountEntry
|
||||
storageView logical.Storage
|
||||
storagePrefix string
|
||||
rootPaths *radix.Tree
|
||||
loginPaths *radix.Tree
|
||||
}
|
||||
|
||||
type validateMountResponse struct {
|
||||
|
@ -89,6 +90,7 @@ func (r *Router) Mount(backend logical.Backend, prefix string, mountEntry *Mount
|
|||
}
|
||||
|
||||
// Build the paths
|
||||
var localView logical.Storage = storageView
|
||||
paths := new(logical.Paths)
|
||||
if backend != nil {
|
||||
specialPaths := backend.SpecialPaths()
|
||||
|
@ -99,18 +101,19 @@ func (r *Router) Mount(backend logical.Backend, prefix string, mountEntry *Mount
|
|||
|
||||
// Create a mount entry
|
||||
re := &routeEntry{
|
||||
tainted: false,
|
||||
backend: backend,
|
||||
mountEntry: mountEntry,
|
||||
storageView: storageView,
|
||||
rootPaths: pathsToRadix(paths.Root),
|
||||
loginPaths: pathsToRadix(paths.Unauthenticated),
|
||||
tainted: false,
|
||||
backend: backend,
|
||||
mountEntry: mountEntry,
|
||||
storagePrefix: storageView.prefix,
|
||||
storageView: localView,
|
||||
rootPaths: pathsToRadix(paths.Root),
|
||||
loginPaths: pathsToRadix(paths.Unauthenticated),
|
||||
}
|
||||
|
||||
switch {
|
||||
case prefix == "":
|
||||
return fmt.Errorf("missing prefix to be used for router entry; mount_path: %q, mount_type: %q", re.mountEntry.Path, re.mountEntry.Type)
|
||||
case storageView.prefix == "":
|
||||
case re.storagePrefix == "":
|
||||
return fmt.Errorf("missing storage view prefix; mount_path: %q, mount_type: %q", re.mountEntry.Path, re.mountEntry.Type)
|
||||
case re.mountEntry.UUID == "":
|
||||
return fmt.Errorf("missing mount identifier; mount_path: %q, mount_type: %q", re.mountEntry.Path, re.mountEntry.Type)
|
||||
|
@ -119,7 +122,7 @@ func (r *Router) Mount(backend logical.Backend, prefix string, mountEntry *Mount
|
|||
}
|
||||
|
||||
r.root.Insert(prefix, re)
|
||||
r.storagePrefix.Insert(storageView.prefix, re)
|
||||
r.storagePrefix.Insert(re.storagePrefix, re)
|
||||
r.mountUUIDCache.Insert(re.mountEntry.UUID, re.mountEntry)
|
||||
r.mountAccessorCache.Insert(re.mountEntry.Accessor, re.mountEntry)
|
||||
|
||||
|
@ -139,11 +142,13 @@ func (r *Router) Unmount(prefix string) error {
|
|||
|
||||
// Call backend's Cleanup routine
|
||||
re := raw.(*routeEntry)
|
||||
re.backend.Cleanup()
|
||||
if re.backend != nil {
|
||||
re.backend.Cleanup()
|
||||
}
|
||||
|
||||
// Purge from the radix trees
|
||||
r.root.Delete(prefix)
|
||||
r.storagePrefix.Delete(re.storageView.prefix)
|
||||
r.storagePrefix.Delete(re.storagePrefix)
|
||||
r.mountUUIDCache.Delete(re.mountEntry.UUID)
|
||||
r.mountAccessorCache.Delete(re.mountEntry.Accessor)
|
||||
|
||||
|
@ -234,10 +239,23 @@ func (r *Router) MatchingMount(path string) string {
|
|||
return mount
|
||||
}
|
||||
|
||||
// MatchingStorageView returns the storageView used for a path
|
||||
func (r *Router) MatchingStorageView(path string) *BarrierView {
|
||||
// MatchingStorageByAPIPath/StoragePath returns the storage used for
|
||||
// API/Storage paths respectively
|
||||
func (r *Router) MatchingStorageByAPIPath(path string) logical.Storage {
|
||||
return r.matchingStorage(path, true)
|
||||
}
|
||||
func (r *Router) MatchingStorageByStoragePath(path string) logical.Storage {
|
||||
return r.matchingStorage(path, false)
|
||||
}
|
||||
func (r *Router) matchingStorage(path string, apiPath bool) logical.Storage {
|
||||
var raw interface{}
|
||||
var ok bool
|
||||
r.l.RLock()
|
||||
_, raw, ok := r.root.LongestPrefix(path)
|
||||
if apiPath {
|
||||
_, raw, ok = r.root.LongestPrefix(path)
|
||||
} else {
|
||||
_, raw, ok = r.storagePrefix.LongestPrefix(path)
|
||||
}
|
||||
r.l.RUnlock()
|
||||
if !ok {
|
||||
return nil
|
||||
|
@ -278,11 +296,23 @@ func (r *Router) MatchingSystemView(path string) logical.SystemView {
|
|||
return raw.(*routeEntry).backend.System()
|
||||
}
|
||||
|
||||
// MatchingStoragePrefix returns the mount path matching and storage prefix
|
||||
// matching the given path
|
||||
func (r *Router) MatchingStoragePrefix(path string) (string, string, bool) {
|
||||
// MatchingStoragePrefixByAPIPath/StoragePath returns the mount path matching
|
||||
// and storage prefix matching the given API/Storage path respectively
|
||||
func (r *Router) MatchingStoragePrefixByAPIPath(path string) (string, string, bool) {
|
||||
return r.matchingStoragePrefix(path, true)
|
||||
}
|
||||
func (r *Router) MatchingStoragePrefixByStoragePath(path string) (string, string, bool) {
|
||||
return r.matchingStoragePrefix(path, false)
|
||||
}
|
||||
func (r *Router) matchingStoragePrefix(path string, apiPath bool) (string, string, bool) {
|
||||
var raw interface{}
|
||||
var ok bool
|
||||
r.l.RLock()
|
||||
_, raw, ok := r.storagePrefix.LongestPrefix(path)
|
||||
if apiPath {
|
||||
_, raw, ok = r.root.LongestPrefix(path)
|
||||
} else {
|
||||
_, raw, ok = r.storagePrefix.LongestPrefix(path)
|
||||
}
|
||||
r.l.RUnlock()
|
||||
if !ok {
|
||||
return "", "", false
|
||||
|
@ -291,10 +321,10 @@ func (r *Router) MatchingStoragePrefix(path string) (string, string, bool) {
|
|||
// Extract the mount path and storage prefix
|
||||
re := raw.(*routeEntry)
|
||||
mountPath := re.mountEntry.Path
|
||||
prefix := re.storageView.prefix
|
||||
prefix := re.storagePrefix
|
||||
|
||||
// Add back the prefix for credential backends
|
||||
if strings.HasPrefix(path, credentialBarrierPrefix) {
|
||||
if !apiPath && strings.HasPrefix(path, credentialBarrierPrefix) {
|
||||
mountPath = credentialRoutePrefix + mountPath
|
||||
}
|
||||
|
||||
|
@ -333,6 +363,11 @@ func (r *Router) routeCommon(req *logical.Request, existenceCheck bool) (*logica
|
|||
strings.Replace(mount, "/", "-", -1)}, time.Now())
|
||||
re := raw.(*routeEntry)
|
||||
|
||||
// Filtered mounts will have a nil backend
|
||||
if re.backend == nil {
|
||||
return logical.ErrorResponse(fmt.Sprintf("no handler for route '%s'", req.Path)), false, false, logical.ErrUnsupportedPath
|
||||
}
|
||||
|
||||
// If the path is tainted, we reject any operation except for
|
||||
// Rollback and Revoke
|
||||
if re.tainted {
|
||||
|
@ -366,7 +401,8 @@ func (r *Router) routeCommon(req *logical.Request, existenceCheck bool) (*logica
|
|||
req.EntityID = ""
|
||||
}
|
||||
|
||||
// Hash the request token unless this is the token backend
|
||||
// Hash the request token unless the request is being routed to the token
|
||||
// or system backend.
|
||||
clientToken := req.ClientToken
|
||||
switch {
|
||||
case strings.HasPrefix(originalPath, "auth/token/"):
|
||||
|
|
|
@ -122,7 +122,7 @@ func TestRouter_Mount(t *testing.T) {
|
|||
t.Fatalf("bad: %s", path)
|
||||
}
|
||||
|
||||
if v := r.MatchingStorageView("prod/aws/foo"); v != view {
|
||||
if v := r.MatchingStorageByAPIPath("prod/aws/foo"); v.(*BarrierView) != view {
|
||||
t.Fatalf("bad: %v", v)
|
||||
}
|
||||
|
||||
|
@ -130,7 +130,7 @@ func TestRouter_Mount(t *testing.T) {
|
|||
t.Fatalf("bad: %s", path)
|
||||
}
|
||||
|
||||
if v := r.MatchingStorageView("stage/aws/foo"); v != nil {
|
||||
if v := r.MatchingStorageByAPIPath("stage/aws/foo"); v != nil {
|
||||
t.Fatalf("bad: %v", v)
|
||||
}
|
||||
|
||||
|
@ -139,7 +139,7 @@ func TestRouter_Mount(t *testing.T) {
|
|||
t.Fatalf("failed to fetch mount entry using its ID; expected: %#v\n actual: %#v\n", mountEntry, mountEntryFetched)
|
||||
}
|
||||
|
||||
mount, prefix, ok := r.MatchingStoragePrefix("logical/foo")
|
||||
mount, prefix, ok := r.MatchingStoragePrefixByStoragePath("logical/foo")
|
||||
if !ok {
|
||||
t.Fatalf("missing storage prefix")
|
||||
}
|
||||
|
@ -200,7 +200,7 @@ func TestRouter_MountCredential(t *testing.T) {
|
|||
t.Fatalf("bad: %s", path)
|
||||
}
|
||||
|
||||
if v := r.MatchingStorageView("auth/aws/foo"); v != view {
|
||||
if v := r.MatchingStorageByAPIPath("auth/aws/foo"); v.(*BarrierView) != view {
|
||||
t.Fatalf("bad: %v", v)
|
||||
}
|
||||
|
||||
|
@ -208,7 +208,7 @@ func TestRouter_MountCredential(t *testing.T) {
|
|||
t.Fatalf("bad: %s", path)
|
||||
}
|
||||
|
||||
if v := r.MatchingStorageView("auth/stage/aws/foo"); v != nil {
|
||||
if v := r.MatchingStorageByAPIPath("auth/stage/aws/foo"); v != nil {
|
||||
t.Fatalf("bad: %v", v)
|
||||
}
|
||||
|
||||
|
@ -217,7 +217,7 @@ func TestRouter_MountCredential(t *testing.T) {
|
|||
t.Fatalf("failed to fetch mount entry using its ID; expected: %#v\n actual: %#v\n", mountEntry, mountEntryFetched)
|
||||
}
|
||||
|
||||
mount, prefix, ok := r.MatchingStoragePrefix("auth/foo")
|
||||
mount, prefix, ok := r.MatchingStoragePrefixByStoragePath("auth/foo")
|
||||
if !ok {
|
||||
t.Fatalf("missing storage prefix")
|
||||
}
|
||||
|
@ -270,7 +270,7 @@ func TestRouter_Unmount(t *testing.T) {
|
|||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
if _, _, ok := r.MatchingStoragePrefix("logical/foo"); ok {
|
||||
if _, _, ok := r.MatchingStoragePrefixByStoragePath("logical/foo"); ok {
|
||||
t.Fatalf("should not have matching storage prefix")
|
||||
}
|
||||
}
|
||||
|
@ -324,7 +324,7 @@ func TestRouter_Remount(t *testing.T) {
|
|||
}
|
||||
|
||||
// Check the resolve from storage still works
|
||||
mount, prefix, _ := r.MatchingStoragePrefix("logical/foobar")
|
||||
mount, prefix, _ := r.MatchingStoragePrefixByStoragePath("logical/foobar")
|
||||
if mount != "stage/aws/" {
|
||||
t.Fatalf("bad mount: %s", mount)
|
||||
}
|
||||
|
|
|
@ -21,11 +21,33 @@ const (
|
|||
barrierSealConfigPath = "core/seal-config"
|
||||
|
||||
// recoverySealConfigPath is the path to the recovery key seal
|
||||
// configuration. It is inside the barrier.
|
||||
// configuration. It lives inside the barrier.
|
||||
// DEPRECATED: Use recoverySealConfigPlaintextPath instead.
|
||||
recoverySealConfigPath = "core/recovery-seal-config"
|
||||
|
||||
// recoverySealConfigPlaintextPath is the path to the recovery key seal
|
||||
// configuration. This is stored in plaintext so that we can perform
|
||||
// auto-unseal.
|
||||
recoverySealConfigPlaintextPath = "core/recovery-config"
|
||||
|
||||
// recoveryKeyPath is the path to the recovery key
|
||||
recoveryKeyPath = "core/recovery-key"
|
||||
|
||||
// hsmStoredKeysPath is the path used for storing HSM-encrypted unseal keys
|
||||
hsmStoredKeysPath = "core/hsm/barrier-unseal-keys"
|
||||
|
||||
// hsmStoredIVPath is the path to the initialization vector for stored keys
|
||||
hsmStoredIVPath = "core/hsm/iv"
|
||||
)
|
||||
|
||||
const (
|
||||
SealTypeShamir = "shamir"
|
||||
SealTypePKCS11 = "hsm-pkcs11-auto"
|
||||
SealTypeAWSKMS = "awskms-auto"
|
||||
SealTypeTest = "test-auto"
|
||||
|
||||
RecoveryTypeUnsupported = "unsupported"
|
||||
RecoveryTypeShamir = "shamir"
|
||||
)
|
||||
|
||||
type KeyNotFoundError struct {
|
||||
|
@ -86,7 +108,7 @@ func (d *DefaultSeal) Finalize() error {
|
|||
}
|
||||
|
||||
func (d *DefaultSeal) BarrierType() string {
|
||||
return "shamir"
|
||||
return SealTypeShamir
|
||||
}
|
||||
|
||||
func (d *DefaultSeal) StoredKeysSupported() bool {
|
||||
|
@ -192,7 +214,7 @@ func (d *DefaultSeal) SetBarrierConfig(config *SealConfig) error {
|
|||
}
|
||||
|
||||
func (d *DefaultSeal) RecoveryType() string {
|
||||
return "unsupported"
|
||||
return RecoveryTypeUnsupported
|
||||
}
|
||||
|
||||
func (d *DefaultSeal) RecoveryConfig() (*SealConfig, error) {
|
||||
|
|
117
vault/testing.go
117
vault/testing.go
|
@ -129,6 +129,7 @@ func TestCoreWithSeal(t testing.T, testSeal Seal, enableRaw bool) *Core {
|
|||
}
|
||||
|
||||
func testCoreConfig(t testing.T, physicalBackend physical.Backend, logger log.Logger) *CoreConfig {
|
||||
t.Helper()
|
||||
noopAudits := map[string]audit.Factory{
|
||||
"noop": func(config *audit.BackendConfig) (audit.Backend, error) {
|
||||
view := &logical.InmemStorage{}
|
||||
|
@ -146,6 +147,7 @@ func testCoreConfig(t testing.T, physicalBackend physical.Backend, logger log.Lo
|
|||
}, nil
|
||||
},
|
||||
}
|
||||
|
||||
noopBackends := make(map[string]logical.Factory)
|
||||
noopBackends["noop"] = func(config *logical.BackendConfig) (logical.Backend, error) {
|
||||
b := new(framework.Backend)
|
||||
|
@ -168,6 +170,7 @@ func testCoreConfig(t testing.T, physicalBackend physical.Backend, logger log.Lo
|
|||
for backendName, backendFactory := range noopBackends {
|
||||
logicalBackends[backendName] = backendFactory
|
||||
}
|
||||
|
||||
logicalBackends["kv"] = LeasedPassthroughBackendFactory
|
||||
for backendName, backendFactory := range testLogicalBackends {
|
||||
logicalBackends[backendName] = backendFactory
|
||||
|
@ -188,26 +191,39 @@ func testCoreConfig(t testing.T, physicalBackend physical.Backend, logger log.Lo
|
|||
// TestCoreInit initializes the core with a single key, and returns
|
||||
// the key that must be used to unseal the core and a root token.
|
||||
func TestCoreInit(t testing.T, core *Core) ([][]byte, string) {
|
||||
return TestCoreInitClusterWrapperSetup(t, core, nil, nil)
|
||||
t.Helper()
|
||||
secretShares, _, root := TestCoreInitClusterWrapperSetup(t, core, nil, nil)
|
||||
return secretShares, root
|
||||
}
|
||||
|
||||
func TestCoreInitClusterWrapperSetup(t testing.T, core *Core, clusterAddrs []*net.TCPAddr, handler http.Handler) ([][]byte, string) {
|
||||
func TestCoreInitClusterWrapperSetup(t testing.T, core *Core, clusterAddrs []*net.TCPAddr, handler http.Handler) ([][]byte, [][]byte, string) {
|
||||
t.Helper()
|
||||
core.SetClusterListenerAddrs(clusterAddrs)
|
||||
core.SetClusterHandler(handler)
|
||||
|
||||
barrierConfig := &SealConfig{
|
||||
SecretShares: 3,
|
||||
SecretThreshold: 3,
|
||||
}
|
||||
|
||||
// If we support storing barrier keys, then set that to equal the min threshold to unseal
|
||||
if core.seal.StoredKeysSupported() {
|
||||
barrierConfig.StoredShares = barrierConfig.SecretThreshold
|
||||
}
|
||||
|
||||
recoveryConfig := &SealConfig{
|
||||
SecretShares: 3,
|
||||
SecretThreshold: 3,
|
||||
}
|
||||
|
||||
result, err := core.Initialize(&InitParams{
|
||||
BarrierConfig: &SealConfig{
|
||||
SecretShares: 3,
|
||||
SecretThreshold: 3,
|
||||
},
|
||||
RecoveryConfig: &SealConfig{
|
||||
SecretShares: 3,
|
||||
SecretThreshold: 3,
|
||||
},
|
||||
BarrierConfig: barrierConfig,
|
||||
RecoveryConfig: recoveryConfig,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
return result.SecretShares, result.RootToken
|
||||
return result.SecretShares, result.RecoveryShares, result.RootToken
|
||||
}
|
||||
|
||||
func TestCoreUnseal(core *Core, key []byte) (bool, error) {
|
||||
|
@ -217,6 +233,7 @@ func TestCoreUnseal(core *Core, key []byte) (bool, error) {
|
|||
// TestCoreUnsealed returns a pure in-memory core that is already
|
||||
// initialized and unsealed.
|
||||
func TestCoreUnsealed(t testing.T) (*Core, [][]byte, string) {
|
||||
t.Helper()
|
||||
core := TestCore(t)
|
||||
return testCoreUnsealed(t, core)
|
||||
}
|
||||
|
@ -224,11 +241,13 @@ func TestCoreUnsealed(t testing.T) (*Core, [][]byte, string) {
|
|||
// TestCoreUnsealedRaw returns a pure in-memory core that is already
|
||||
// initialized, unsealed, and with raw endpoints enabled.
|
||||
func TestCoreUnsealedRaw(t testing.T) (*Core, [][]byte, string) {
|
||||
t.Helper()
|
||||
core := TestCoreRaw(t)
|
||||
return testCoreUnsealed(t, core)
|
||||
}
|
||||
|
||||
func testCoreUnsealed(t testing.T, core *Core) (*Core, [][]byte, string) {
|
||||
t.Helper()
|
||||
keys, token := TestCoreInit(t, core)
|
||||
for _, key := range keys {
|
||||
if _, err := TestCoreUnseal(core, TestKeyCopy(key)); err != nil {
|
||||
|
@ -248,6 +267,7 @@ func testCoreUnsealed(t testing.T, core *Core) (*Core, [][]byte, string) {
|
|||
}
|
||||
|
||||
func TestCoreUnsealedBackend(t testing.T, backend physical.Backend) (*Core, [][]byte, string) {
|
||||
t.Helper()
|
||||
logger := logformat.NewVaultLogger(log.LevelTrace)
|
||||
conf := testCoreConfig(t, backend, logger)
|
||||
conf.Seal = NewTestSeal(t, nil)
|
||||
|
@ -264,6 +284,10 @@ func TestCoreUnsealedBackend(t testing.T, backend physical.Backend) (*Core, [][]
|
|||
}
|
||||
}
|
||||
|
||||
if err := core.UnsealWithStoredKeys(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
sealed, err := core.Sealed()
|
||||
if err != nil {
|
||||
t.Fatalf("err checking seal status: %s", err)
|
||||
|
@ -655,6 +679,7 @@ func TestWaitActive(t testing.T, core *Core) {
|
|||
|
||||
type TestCluster struct {
|
||||
BarrierKeys [][]byte
|
||||
RecoveryKeys [][]byte
|
||||
CACert *x509.Certificate
|
||||
CACertBytes []byte
|
||||
CACertPEM []byte
|
||||
|
@ -737,18 +762,19 @@ type TestListener struct {
|
|||
|
||||
type TestClusterCore struct {
|
||||
*Core
|
||||
Client *api.Client
|
||||
Handler http.Handler
|
||||
Listeners []*TestListener
|
||||
ReloadFuncs *map[string][]reload.ReloadFunc
|
||||
ReloadFuncsLock *sync.RWMutex
|
||||
Server *http.Server
|
||||
ServerCert *x509.Certificate
|
||||
ServerCertBytes []byte
|
||||
ServerCertPEM []byte
|
||||
ServerKey *ecdsa.PrivateKey
|
||||
ServerKeyPEM []byte
|
||||
TLSConfig *tls.Config
|
||||
Client *api.Client
|
||||
Handler http.Handler
|
||||
Listeners []*TestListener
|
||||
ReloadFuncs *map[string][]reload.ReloadFunc
|
||||
ReloadFuncsLock *sync.RWMutex
|
||||
Server *http.Server
|
||||
ServerCert *x509.Certificate
|
||||
ServerCertBytes []byte
|
||||
ServerCertPEM []byte
|
||||
ServerKey *ecdsa.PrivateKey
|
||||
ServerKeyPEM []byte
|
||||
TLSConfig *tls.Config
|
||||
UnderlyingStorage physical.Backend
|
||||
}
|
||||
|
||||
type TestClusterOptions struct {
|
||||
|
@ -757,6 +783,7 @@ type TestClusterOptions struct {
|
|||
HandlerFunc func(*Core) http.Handler
|
||||
BaseListenAddress string
|
||||
NumCores int
|
||||
SealFunc func() Seal
|
||||
}
|
||||
|
||||
var DefaultNumCores = 3
|
||||
|
@ -771,6 +798,12 @@ type certInfo struct {
|
|||
|
||||
// NewTestCluster creates a new test cluster based on the provided core config
|
||||
// and test cluster options.
|
||||
//
|
||||
// N.B. Even though a single base CoreConfig is provided, NewTestCluster will instantiate a
|
||||
// core config for each core it creates. If separate seal per core is desired, opts.SealFunc
|
||||
// can be provided to generate a seal for each one. Otherwise, the provided base.Seal will be
|
||||
// shared among cores. NewCore's default behavior is to generate a new DefaultSeal if the
|
||||
// provided Seal in coreConfig (i.e. base.Seal) is nil.
|
||||
func NewTestCluster(t testing.T, base *CoreConfig, opts *TestClusterOptions) *TestCluster {
|
||||
var numCores int
|
||||
if opts == nil || opts.NumCores == 0 {
|
||||
|
@ -1077,6 +1110,12 @@ func NewTestCluster(t testing.T, base *CoreConfig, opts *TestClusterOptions) *Te
|
|||
if coreConfig.ClusterAddr != "" {
|
||||
coreConfig.ClusterAddr = fmt.Sprintf("https://127.0.0.1:%d", listeners[i][0].Address.Port+105)
|
||||
}
|
||||
|
||||
// if opts.SealFunc is provided, use that to generate a seal for the config instead
|
||||
if opts != nil && opts.SealFunc != nil {
|
||||
coreConfig.Seal = opts.SealFunc()
|
||||
}
|
||||
|
||||
c, err := NewCore(coreConfig)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
|
@ -1110,9 +1149,11 @@ func NewTestCluster(t testing.T, base *CoreConfig, opts *TestClusterOptions) *Te
|
|||
}
|
||||
|
||||
if opts == nil || !opts.SkipInit {
|
||||
keys, root := TestCoreInitClusterWrapperSetup(t, cores[0], clusterAddrGen(listeners[0]), handlers[0])
|
||||
barrierKeys, _ := copystructure.Copy(keys)
|
||||
bKeys, rKeys, root := TestCoreInitClusterWrapperSetup(t, cores[0], clusterAddrGen(listeners[0]), handlers[0])
|
||||
barrierKeys, _ := copystructure.Copy(bKeys)
|
||||
testCluster.BarrierKeys = barrierKeys.([][]byte)
|
||||
recoveryKeys, _ := copystructure.Copy(rKeys)
|
||||
testCluster.RecoveryKeys = recoveryKeys.([][]byte)
|
||||
testCluster.RootToken = root
|
||||
|
||||
// Write root token and barrier keys
|
||||
|
@ -1131,14 +1172,30 @@ func NewTestCluster(t testing.T, base *CoreConfig, opts *TestClusterOptions) *Te
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for i, key := range testCluster.RecoveryKeys {
|
||||
buf.Write([]byte(base64.StdEncoding.EncodeToString(key)))
|
||||
if i < len(testCluster.RecoveryKeys)-1 {
|
||||
buf.WriteRune('\n')
|
||||
}
|
||||
}
|
||||
err = ioutil.WriteFile(filepath.Join(testCluster.TempDir, "recovery_keys"), buf.Bytes(), 0755)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Unseal first core
|
||||
for _, key := range keys {
|
||||
for _, key := range bKeys {
|
||||
if _, err := cores[0].Unseal(TestKeyCopy(key)); err != nil {
|
||||
t.Fatalf("unseal err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// If stored keys is supported, the above will no no-op, so trigger auto-unseal
|
||||
// using stored keys to try to unseal
|
||||
if err := cores[0].UnsealWithStoredKeys(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Verify unsealed
|
||||
sealed, err := cores[0].Sealed()
|
||||
if err != nil {
|
||||
|
@ -1153,11 +1210,17 @@ func NewTestCluster(t testing.T, base *CoreConfig, opts *TestClusterOptions) *Te
|
|||
// Unseal other cores unless otherwise specified
|
||||
if (opts == nil || !opts.KeepStandbysSealed) && numCores > 1 {
|
||||
for i := 1; i < numCores; i++ {
|
||||
for _, key := range keys {
|
||||
for _, key := range bKeys {
|
||||
if _, err := cores[i].Unseal(TestKeyCopy(key)); err != nil {
|
||||
t.Fatalf("unseal err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// If stored keys is supported, the above will no no-op, so trigger auto-unseal
|
||||
// using stored keys
|
||||
if err := cores[i].UnsealWithStoredKeys(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Let them come fully up to standby
|
||||
|
|
|
@ -121,7 +121,9 @@ func NewTokenStore(c *Core, config *logical.BackendConfig) (*TokenStore, error)
|
|||
}
|
||||
|
||||
if c.policyStore != nil {
|
||||
t.policyLookupFunc = c.policyStore.GetPolicy
|
||||
t.policyLookupFunc = func(name string) (*Policy, error) {
|
||||
return c.policyStore.GetPolicy(name, PolicyTypeToken)
|
||||
}
|
||||
}
|
||||
|
||||
// Setup the framework endpoints
|
||||
|
@ -497,7 +499,7 @@ func (ts *TokenStore) Initialize() error {
|
|||
}
|
||||
|
||||
func (ts *TokenStore) Invalidate(key string) {
|
||||
ts.logger.Trace("token: invalidating key", "key", key)
|
||||
//ts.logger.Trace("token: invalidating key", "key", key)
|
||||
|
||||
switch key {
|
||||
case tokenSubPath + salt.DefaultLocation:
|
||||
|
@ -530,13 +532,13 @@ func (ts *TokenStore) Salt() (*salt.Salt, error) {
|
|||
// TokenEntry is used to represent a given token
|
||||
type TokenEntry struct {
|
||||
// ID of this entry, generally a random UUID
|
||||
ID string `json:"id" mapstructure:"id" structs:"id"`
|
||||
ID string `json:"id" mapstructure:"id" structs:"id" sentinel:""`
|
||||
|
||||
// Accessor for this token, a random UUID
|
||||
Accessor string `json:"accessor" mapstructure:"accessor" structs:"accessor"`
|
||||
Accessor string `json:"accessor" mapstructure:"accessor" structs:"accessor" sentinel:""`
|
||||
|
||||
// Parent token, used for revocation trees
|
||||
Parent string `json:"parent" mapstructure:"parent" structs:"parent"`
|
||||
Parent string `json:"parent" mapstructure:"parent" structs:"parent" sentinel:""`
|
||||
|
||||
// Which named policies should be used
|
||||
Policies []string `json:"policies" mapstructure:"policies" structs:"policies"`
|
||||
|
@ -545,7 +547,7 @@ type TokenEntry struct {
|
|||
Path string `json:"path" mapstructure:"path" structs:"path"`
|
||||
|
||||
// Used for auditing. This could include things like "source", "user", "ip"
|
||||
Meta map[string]string `json:"meta" mapstructure:"meta" structs:"meta"`
|
||||
Meta map[string]string `json:"meta" mapstructure:"meta" structs:"meta" sentinel:"meta"`
|
||||
|
||||
// Used for operators to be able to associate with the source
|
||||
DisplayName string `json:"display_name" mapstructure:"display_name" structs:"display_name"`
|
||||
|
@ -560,13 +562,13 @@ type TokenEntry struct {
|
|||
NumUses int `json:"num_uses" mapstructure:"num_uses" structs:"num_uses"`
|
||||
|
||||
// Time of token creation
|
||||
CreationTime int64 `json:"creation_time" mapstructure:"creation_time" structs:"creation_time"`
|
||||
CreationTime int64 `json:"creation_time" mapstructure:"creation_time" structs:"creation_time" sentinel:""`
|
||||
|
||||
// Duration set when token was created
|
||||
TTL time.Duration `json:"ttl" mapstructure:"ttl" structs:"ttl"`
|
||||
TTL time.Duration `json:"ttl" mapstructure:"ttl" structs:"ttl" sentinel:""`
|
||||
|
||||
// Explicit maximum TTL on the token
|
||||
ExplicitMaxTTL time.Duration `json:"explicit_max_ttl" mapstructure:"explicit_max_ttl" structs:"explicit_max_ttl"`
|
||||
ExplicitMaxTTL time.Duration `json:"explicit_max_ttl" mapstructure:"explicit_max_ttl" structs:"explicit_max_ttl" sentinel:""`
|
||||
|
||||
// If set, the role that was used for parameters at creation time
|
||||
Role string `json:"role" mapstructure:"role" structs:"role"`
|
||||
|
@ -574,17 +576,53 @@ type TokenEntry struct {
|
|||
// If set, the period of the token. This is only used when created directly
|
||||
// through the create endpoint; periods managed by roles or other auth
|
||||
// backends are subject to those renewal rules.
|
||||
Period time.Duration `json:"period" mapstructure:"period" structs:"period"`
|
||||
Period time.Duration `json:"period" mapstructure:"period" structs:"period" sentinel:""`
|
||||
|
||||
// These are the deprecated fields
|
||||
DisplayNameDeprecated string `json:"DisplayName" mapstructure:"DisplayName" structs:"DisplayName"`
|
||||
NumUsesDeprecated int `json:"NumUses" mapstructure:"NumUses" structs:"NumUses"`
|
||||
CreationTimeDeprecated int64 `json:"CreationTime" mapstructure:"CreationTime" structs:"CreationTime"`
|
||||
ExplicitMaxTTLDeprecated time.Duration `json:"ExplicitMaxTTL" mapstructure:"ExplicitMaxTTL" structs:"ExplicitMaxTTL"`
|
||||
DisplayNameDeprecated string `json:"DisplayName" mapstructure:"DisplayName" structs:"DisplayName" sentinel:""`
|
||||
NumUsesDeprecated int `json:"NumUses" mapstructure:"NumUses" structs:"NumUses" sentinel:""`
|
||||
CreationTimeDeprecated int64 `json:"CreationTime" mapstructure:"CreationTime" structs:"CreationTime" sentinel:""`
|
||||
ExplicitMaxTTLDeprecated time.Duration `json:"ExplicitMaxTTL" mapstructure:"ExplicitMaxTTL" structs:"ExplicitMaxTTL" sentinel:""`
|
||||
|
||||
EntityID string `json:"entity_id" mapstructure:"entity_id" structs:"entity_id"`
|
||||
}
|
||||
|
||||
func (te *TokenEntry) SentinelGet(key string) (interface{}, error) {
|
||||
if te == nil {
|
||||
return nil, nil
|
||||
}
|
||||
switch key {
|
||||
case "period":
|
||||
return te.Period, nil
|
||||
|
||||
case "period_seconds":
|
||||
return int64(te.Period.Seconds()), nil
|
||||
|
||||
case "explicit_max_ttl":
|
||||
return te.ExplicitMaxTTL, nil
|
||||
|
||||
case "explicit_max_ttl_seconds":
|
||||
return int64(te.ExplicitMaxTTL.Seconds()), nil
|
||||
|
||||
case "creation_ttl":
|
||||
return te.TTL, nil
|
||||
|
||||
case "creation_ttl_seconds":
|
||||
return int64(te.TTL.Seconds()), nil
|
||||
|
||||
case "creation_time":
|
||||
return time.Unix(te.CreationTime, 0).Format(time.RFC3339Nano), nil
|
||||
|
||||
case "creation_time_unix":
|
||||
return time.Unix(te.CreationTime, 0), nil
|
||||
|
||||
case "meta", "metadata":
|
||||
return te.Meta, nil
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// tsRoleEntry contains token store role information
|
||||
type tsRoleEntry struct {
|
||||
// The name of the role. Embedded so it can be used for pathing
|
||||
|
@ -698,8 +736,8 @@ func (ts *TokenStore) createAccessor(entry *TokenEntry) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
path := accessorPrefix + saltID
|
||||
|
||||
path := accessorPrefix + saltID
|
||||
aEntry := &accessorEntry{
|
||||
TokenID: entry.ID,
|
||||
AccessorID: entry.Accessor,
|
||||
|
@ -2021,7 +2059,6 @@ func (ts *TokenStore) handleLookup(
|
|||
return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest
|
||||
}
|
||||
out, err := ts.lookupSalted(saltedId, true)
|
||||
|
||||
if err != nil {
|
||||
return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest
|
||||
}
|
||||
|
|
|
@ -222,8 +222,11 @@ func testCoreMakeToken(t *testing.T, c *Core, root, client, ttl string, policy [
|
|||
if err != nil {
|
||||
t.Fatalf("err: %v %v", err, resp)
|
||||
}
|
||||
if resp.IsError() {
|
||||
t.Fatalf("err: %v %v", err, *resp)
|
||||
}
|
||||
if resp.Auth.ClientToken != client {
|
||||
t.Fatalf("bad: %#v", resp)
|
||||
t.Fatalf("bad: %#v", *resp)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1109,7 +1112,7 @@ func TestTokenStore_HandleRequest_CreateToken_NonRoot_RootChild(t *testing.T) {
|
|||
core, ts, _, root := TestCoreWithTokenStore(t)
|
||||
ps := core.policyStore
|
||||
|
||||
policy, _ := Parse(tokenCreationPolicy)
|
||||
policy, _ := ParseACLPolicy(tokenCreationPolicy)
|
||||
policy.Name = "test1"
|
||||
if err := ps.SetPolicy(policy); err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -1965,19 +1968,19 @@ func TestTokenStore_RoleDisallowedPolicies(t *testing.T) {
|
|||
ps := core.policyStore
|
||||
|
||||
// Create 3 different policies
|
||||
policy, _ := Parse(tokenCreationPolicy)
|
||||
policy, _ := ParseACLPolicy(tokenCreationPolicy)
|
||||
policy.Name = "test1"
|
||||
if err := ps.SetPolicy(policy); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
policy, _ = Parse(tokenCreationPolicy)
|
||||
policy, _ = ParseACLPolicy(tokenCreationPolicy)
|
||||
policy.Name = "test2"
|
||||
if err := ps.SetPolicy(policy); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
policy, _ = Parse(tokenCreationPolicy)
|
||||
policy, _ = ParseACLPolicy(tokenCreationPolicy)
|
||||
policy.Name = "test3"
|
||||
if err := ps.SetPolicy(policy); err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -2894,7 +2897,7 @@ func TestTokenStore_NoDefaultPolicy(t *testing.T) {
|
|||
|
||||
core, ts, _, root := TestCoreWithTokenStore(t)
|
||||
ps := core.policyStore
|
||||
policy, _ := Parse(tokenCreationPolicy)
|
||||
policy, _ := ParseACLPolicy(tokenCreationPolicy)
|
||||
policy.Name = "policy1"
|
||||
if err := ps.SetPolicy(policy); err != nil {
|
||||
t.Fatal(err)
|
||||
|
|
Loading…
Reference in New Issue