consul: ACL enforcement for KV updates

This commit is contained in:
Armon Dadgar 2014-08-14 19:25:12 -07:00
parent 705c6cdb86
commit 25855b2362
2 changed files with 88 additions and 4 deletions

View File

@ -26,6 +26,23 @@ func (k *KVS) Apply(args *structs.KVSRequest, reply *bool) error {
return fmt.Errorf("Must provide key")
}
// Apply the ACL policy if any
acl, err := k.srv.resolveToken(args.Token)
if err != nil {
return err
} else if acl != nil {
switch args.Op {
case structs.KVSDeleteTree:
if !acl.KeyWritePrefix(args.DirEnt.Key) {
return permissionDeniedErr
}
default:
if !acl.KeyWrite(args.DirEnt.Key) {
return permissionDeniedErr
}
}
}
// If this is a lock, we must check for a lock-delay. Since lock-delay
// is based on wall-time, each peer expire the lock-delay at a slightly
// different time. This means the enforcement of lock-delay cannot be done

View File

@ -1,11 +1,13 @@
package consul
import (
"github.com/hashicorp/consul/consul/structs"
"github.com/hashicorp/consul/testutil"
"os"
"strings"
"testing"
"time"
"github.com/hashicorp/consul/consul/structs"
"github.com/hashicorp/consul/testutil"
)
func TestKVS_Apply(t *testing.T) {
@ -64,6 +66,68 @@ func TestKVS_Apply(t *testing.T) {
}
}
func TestKVS_Apply_ACLDeny(t *testing.T) {
dir1, s1 := testServerWithConfig(t, func(c *Config) {
c.ACLDatacenter = "dc1"
c.ACLMasterToken = "root"
c.ACLDefaultPolicy = "deny"
})
defer os.RemoveAll(dir1)
defer s1.Shutdown()
client := rpcClient(t, s1)
defer client.Close()
testutil.WaitForLeader(t, client.Call, "dc1")
// Create the ACL
arg := structs.ACLRequest{
Datacenter: "dc1",
Op: structs.ACLSet,
ACL: structs.ACL{
Name: "User token",
Type: structs.ACLTypeClient,
Rules: testListRules,
},
WriteRequest: structs.WriteRequest{Token: "root"},
}
var out string
if err := client.Call("ACL.Apply", &arg, &out); err != nil {
t.Fatalf("err: %v", err)
}
id := out
// Try a write
argR := structs.KVSRequest{
Datacenter: "dc1",
Op: structs.KVSSet,
DirEnt: structs.DirEntry{
Key: "foo/bar",
Flags: 42,
Value: []byte("test"),
},
WriteRequest: structs.WriteRequest{Token: id},
}
var outR bool
err := client.Call("KVS.Apply", &argR, &outR)
if err == nil || !strings.Contains(err.Error(), permissionDenied) {
t.Fatalf("err: %v", err)
}
// Try a recursive delete
argR = structs.KVSRequest{
Datacenter: "dc1",
Op: structs.KVSDeleteTree,
DirEnt: structs.DirEntry{
Key: "test",
},
WriteRequest: structs.WriteRequest{Token: id},
}
err = client.Call("KVS.Apply", &argR, &outR)
if err == nil || !strings.Contains(err.Error(), permissionDenied) {
t.Fatalf("err: %v", err)
}
}
func TestKVS_Get(t *testing.T) {
dir1, s1 := testServer(t)
defer os.RemoveAll(dir1)
@ -128,7 +192,7 @@ func TestKVS_Get_ACLDeny(t *testing.T) {
Datacenter: "dc1",
Op: structs.KVSSet,
DirEnt: structs.DirEntry{
Key: "test",
Key: "zip",
Flags: 42,
Value: []byte("test"),
},
@ -141,7 +205,7 @@ func TestKVS_Get_ACLDeny(t *testing.T) {
getR := structs.KeyRequest{
Datacenter: "dc1",
Key: "test",
Key: "zip",
}
var dirent structs.IndexedDirEntries
if err := client.Call("KVS.Get", &getR, &dirent); err != nil {
@ -512,4 +576,7 @@ key "foo" {
key "test" {
policy = "write"
}
key "test/priv" {
policy = "read"
}
`