vault: Support policy CRUD
This commit is contained in:
parent
192dcf7d39
commit
f40ed182c4
|
@ -17,6 +17,8 @@ func NewSystemBackend(core *Core) logical.Backend {
|
|||
"auth/*",
|
||||
"remount",
|
||||
"revoke-prefix/*",
|
||||
"policy",
|
||||
"policy/*",
|
||||
},
|
||||
|
||||
Paths: []*framework.Path{
|
||||
|
@ -176,6 +178,41 @@ func NewSystemBackend(core *Core) logical.Backend {
|
|||
HelpSynopsis: strings.TrimSpace(sysHelp["auth"][0]),
|
||||
HelpDescription: strings.TrimSpace(sysHelp["auth"][1]),
|
||||
},
|
||||
|
||||
&framework.Path{
|
||||
Pattern: "policy$",
|
||||
|
||||
Callbacks: map[logical.Operation]framework.OperationFunc{
|
||||
logical.ReadOperation: b.handlePolicyList,
|
||||
},
|
||||
|
||||
HelpSynopsis: strings.TrimSpace(sysHelp["policy-list"][0]),
|
||||
HelpDescription: strings.TrimSpace(sysHelp["policy-list"][1]),
|
||||
},
|
||||
|
||||
&framework.Path{
|
||||
Pattern: "policy/(?P<name>.+)",
|
||||
|
||||
Fields: map[string]*framework.FieldSchema{
|
||||
"name": &framework.FieldSchema{
|
||||
Type: framework.TypeString,
|
||||
Description: strings.TrimSpace(sysHelp["policy-name"][0]),
|
||||
},
|
||||
"rules": &framework.FieldSchema{
|
||||
Type: framework.TypeString,
|
||||
Description: strings.TrimSpace(sysHelp["policy-rules"][0]),
|
||||
},
|
||||
},
|
||||
|
||||
Callbacks: map[logical.Operation]framework.OperationFunc{
|
||||
logical.ReadOperation: b.handlePolicyRead,
|
||||
logical.WriteOperation: b.handlePolicySet,
|
||||
logical.DeleteOperation: b.handlePolicyDelete,
|
||||
},
|
||||
|
||||
HelpSynopsis: strings.TrimSpace(sysHelp["policy"][0]),
|
||||
HelpDescription: strings.TrimSpace(sysHelp["policy"][1]),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -383,6 +420,71 @@ func (b *SystemBackend) handleDisableAuth(
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
// handlePolicyList handles the "policy" endpoint to provide the enabled policies
|
||||
func (b *SystemBackend) handlePolicyList(
|
||||
req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
|
||||
// Get all the configured policies
|
||||
policies, err := b.Core.policy.ListPolicies()
|
||||
|
||||
// Add the special "root" policy
|
||||
policies = append(policies, "root")
|
||||
return logical.ListResponse(policies), err
|
||||
}
|
||||
|
||||
// handlePolicyRead handles the "policy/<name>" endpoint to read a policy
|
||||
func (b *SystemBackend) handlePolicyRead(
|
||||
req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
|
||||
name := data.Get("name").(string)
|
||||
|
||||
policy, err := b.Core.policy.GetPolicy(name)
|
||||
if err != nil {
|
||||
return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest
|
||||
}
|
||||
|
||||
if policy == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &logical.Response{
|
||||
Data: map[string]interface{}{
|
||||
"name": name,
|
||||
"rules": policy.Raw,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// handlePolicySet handles the "policy/<name>" endpoint to set a policy
|
||||
func (b *SystemBackend) handlePolicySet(
|
||||
req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
|
||||
name := data.Get("name").(string)
|
||||
rules := data.Get("rules").(string)
|
||||
|
||||
// Validate the rules parse
|
||||
parse, err := Parse(rules)
|
||||
if err != nil {
|
||||
return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest
|
||||
}
|
||||
|
||||
// Override the name
|
||||
parse.Name = name
|
||||
|
||||
// Update the policy
|
||||
if err := b.Core.policy.SetPolicy(parse); err != nil {
|
||||
return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// handlePolicyDelete handles the "policy/<name>" endpoint to delete a policy
|
||||
func (b *SystemBackend) handlePolicyDelete(
|
||||
req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
|
||||
name := data.Get("name").(string)
|
||||
if err := b.Core.policy.DeletePolicy(name); err != nil {
|
||||
return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// sysHelp is all the help text for the sys backend.
|
||||
var sysHelp = map[string][2]string{
|
||||
"mounts": {
|
||||
|
@ -513,4 +615,30 @@ Example: you might have an OAuth backend for GitHub, and one for Google Apps.
|
|||
`User-friendly description for this crential backend.`,
|
||||
"",
|
||||
},
|
||||
|
||||
"policy-list": {
|
||||
`List the configured access control policies.`,
|
||||
`
|
||||
List the names of the configured access control policies. Policies are associated
|
||||
with client tokens to limit access to keys in the Vault.
|
||||
`,
|
||||
},
|
||||
|
||||
"policy": {
|
||||
`Read, Modify, or Delete an access control policy.`,
|
||||
`
|
||||
Read the rules of an existing policy, create or update the rules of a policy,
|
||||
or delete a policy.
|
||||
`,
|
||||
},
|
||||
|
||||
"policy-name": {
|
||||
`The name of the policy. Example: "ops"`,
|
||||
"",
|
||||
},
|
||||
|
||||
"policy-rules": {
|
||||
`The rules of the policy. Either given in HCL or JSON format.`,
|
||||
"",
|
||||
},
|
||||
}
|
||||
|
|
|
@ -14,6 +14,8 @@ func TestSystemBackend_RootPaths(t *testing.T) {
|
|||
"auth/*",
|
||||
"remount",
|
||||
"revoke-prefix/*",
|
||||
"policy",
|
||||
"policy/*",
|
||||
}
|
||||
|
||||
b := testSystemBackend(t)
|
||||
|
@ -392,6 +394,101 @@ func TestSystemBackend_disableAuth_invalid(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestSystemBackend_policyList(t *testing.T) {
|
||||
b := testSystemBackend(t)
|
||||
req := logical.TestRequest(t, logical.ReadOperation, "policy")
|
||||
resp, err := b.HandleRequest(req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
exp := map[string]interface{}{
|
||||
"keys": []string{"root"},
|
||||
}
|
||||
if !reflect.DeepEqual(resp.Data, exp) {
|
||||
t.Fatalf("got: %#v expect: %#v", resp.Data, exp)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSystemBackend_policyCRUD(t *testing.T) {
|
||||
b := testSystemBackend(t)
|
||||
|
||||
// Create the policy
|
||||
rules := `path "foo/" { policy = "read" }`
|
||||
req := logical.TestRequest(t, logical.WriteOperation, "policy/foo")
|
||||
req.Data["rules"] = rules
|
||||
resp, err := b.HandleRequest(req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v %#v", err, resp)
|
||||
}
|
||||
if resp != nil {
|
||||
t.Fatalf("bad: %#v", resp)
|
||||
}
|
||||
|
||||
// Read the policy
|
||||
req = logical.TestRequest(t, logical.ReadOperation, "policy/foo")
|
||||
resp, err = b.HandleRequest(req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
exp := map[string]interface{}{
|
||||
"name": "foo",
|
||||
"rules": rules,
|
||||
}
|
||||
if !reflect.DeepEqual(resp.Data, exp) {
|
||||
t.Fatalf("got: %#v expect: %#v", resp.Data, exp)
|
||||
}
|
||||
|
||||
// List the policies
|
||||
req = logical.TestRequest(t, logical.ReadOperation, "policy")
|
||||
resp, err = b.HandleRequest(req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
exp = map[string]interface{}{
|
||||
"keys": []string{"foo", "root"},
|
||||
}
|
||||
if !reflect.DeepEqual(resp.Data, exp) {
|
||||
t.Fatalf("got: %#v expect: %#v", resp.Data, exp)
|
||||
}
|
||||
|
||||
// Delete the policy
|
||||
req = logical.TestRequest(t, logical.DeleteOperation, "policy/foo")
|
||||
resp, err = b.HandleRequest(req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
if resp != nil {
|
||||
t.Fatalf("bad: %#v", resp)
|
||||
}
|
||||
|
||||
// Read the policy (deleted)
|
||||
req = logical.TestRequest(t, logical.ReadOperation, "policy/foo")
|
||||
resp, err = b.HandleRequest(req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
if resp != nil {
|
||||
t.Fatalf("bad: %#v", resp)
|
||||
}
|
||||
|
||||
// List the policies (deleted)
|
||||
req = logical.TestRequest(t, logical.ReadOperation, "policy")
|
||||
resp, err = b.HandleRequest(req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
exp = map[string]interface{}{
|
||||
"keys": []string{"root"},
|
||||
}
|
||||
if !reflect.DeepEqual(resp.Data, exp) {
|
||||
t.Fatalf("got: %#v expect: %#v", resp.Data, exp)
|
||||
}
|
||||
}
|
||||
|
||||
func testSystemBackend(t *testing.T) logical.Backend {
|
||||
c, _ := TestCoreUnsealed(t)
|
||||
return NewSystemBackend(c)
|
||||
|
|
|
@ -46,11 +46,6 @@ func Parse(rules string) (*Policy, error) {
|
|||
return nil, fmt.Errorf("Failed to parse ACL rules: %v", err)
|
||||
}
|
||||
|
||||
// Validate a name is given
|
||||
if p.Name == "" {
|
||||
return nil, fmt.Errorf("Policy name is missing")
|
||||
}
|
||||
|
||||
// Validate the path policy
|
||||
for _, pp := range p.Paths {
|
||||
switch pp.Policy {
|
||||
|
|
Loading…
Reference in New Issue