forked from hashicorp/vault
-
Notifications
You must be signed in to change notification settings - Fork 0
/
policy_store.go
231 lines (200 loc) · 5.46 KB
/
policy_store.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
package vault
import (
"fmt"
"time"
"github.com/armon/go-metrics"
"github.com/hashicorp/errwrap"
"github.com/hashicorp/golang-lru"
"github.com/hashicorp/vault/logical"
)
const (
// policySubPath is the sub-path used for the policy store
// view. This is nested under the system view.
policySubPath = "policy/"
// policyCacheSize is the number of policies that are kept cached
policyCacheSize = 1024
)
// PolicyStore is used to provide durable storage of policy, and to
// manage ACLs associated with them.
type PolicyStore struct {
view *BarrierView
lru *lru.Cache
}
// PolicyEntry is used to store a policy by name
type PolicyEntry struct {
Version int
Raw string
}
// 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) *PolicyStore {
cache, _ := lru.New(policyCacheSize)
p := &PolicyStore{
view: view,
lru: cache,
}
return p
}
// 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
c.policyStore = NewPolicyStore(view)
// Ensure that the default policy exists, and if not, create it
policy, err := c.policyStore.GetPolicy("default")
if err != nil {
return errwrap.Wrapf("error fetching default policy from store: {{err}}", err)
}
if policy == nil {
err := c.policyStore.createDefaultPolicy()
if err != nil {
return err
}
}
return nil
}
// teardownPolicyStore is used to reverse setupPolicyStore
// when the vault is being sealed.
func (c *Core) teardownPolicyStore() error {
c.policyStore = nil
return nil
}
// 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.Name == "root" {
return fmt.Errorf("cannot update root policy")
}
if p.Name == "" {
return fmt.Errorf("policy name missing")
}
// Create the entry
entry, err := logical.StorageEntryJSON(p.Name, &PolicyEntry{
Version: 2,
Raw: p.Raw,
})
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)
}
// 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) {
defer metrics.MeasureSince([]string{"policy", "get_policy"}, time.Now())
// Check for cached policy
if raw, ok := ps.lru.Get(name); ok {
return raw.(*Policy), nil
}
// Special case the root policy
if name == "root" {
p := &Policy{Name: "root"}
ps.lru.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)
}
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
} else {
// On error, attempt to use V1 parsing
p, err := Parse(string(out.Value))
if err != nil {
return nil, fmt.Errorf("failed to parse policy: %v", err)
}
p.Name = name
// V1 used implicit glob, we need to do a fix-up
for _, pp := range p.Paths {
pp.Glob = true
}
policy = p
}
// Update the LRU cache
ps.lru.Add(name, policy)
return policy, nil
}
// ListPolicies is used to list the available policies
func (ps *PolicyStore) ListPolicies() ([]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.
return CollectKeys(ps.view)
}
// DeletePolicy is used to delete the named policy
func (ps *PolicyStore) DeletePolicy(name string) error {
defer metrics.MeasureSince([]string{"policy", "delete_policy"}, time.Now())
if name == "root" {
return fmt.Errorf("cannot delete root policy")
}
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)
}
// Clear the cache
ps.lru.Remove(name)
return nil
}
// ACL is used to return an ACL which is built using the
// named policies.
func (ps *PolicyStore) ACL(names ...string) (*ACL, error) {
// Fetch the policies
var policy []*Policy
for _, name := range names {
p, err := ps.GetPolicy(name)
if err != nil {
return nil, fmt.Errorf("failed to get policy '%s': %v", name, err)
}
policy = append(policy, p)
}
// Construct the ACL
acl, err := NewACL(policy)
if err != nil {
return nil, fmt.Errorf("failed to construct ACL: %v", err)
}
return acl, nil
}
func (ps *PolicyStore) createDefaultPolicy() error {
policy, err := Parse(`
path "auth/token/lookup-self" {
policy = "read"
}
path "auth/token/renew-self" {
policy = "write"
}
path "auth/token/revoke-self" {
policy = "write"
}
`)
if err != nil {
return errwrap.Wrapf("error parsing default policy: {{err}}", err)
}
if policy == nil {
return fmt.Errorf("parsing default policy resulted in nil policy")
}
policy.Name = "default"
return ps.SetPolicy(policy)
}