etcdctl: an option for granting permission with key prefix
This commit adds a new option --prefix to "role grant-permission" command. If the option is passed, the command interprets the key as a prefix of range permission. Example of usage: $ ETCDCTL_API=3 bin/etcdctl --user root:p role grant-permission --prefix r1 readwrite /dir/ Role r1 updated $ ETCDCTL_API=3 bin/etcdctl --user root:p role get r1 Role r1 KV Read: [/dir/, /dir0) [k1, k5) KV Write: [/dir/, /dir0) [k1, k5) $ ETCDCTL_API=3 bin/etcdctl --user u1:p put /dir/key val OK
This commit is contained in:

committed by
Hitoshi Mitake

parent
3df8838501
commit
4e2b09a7ca
@ -17,6 +17,8 @@ package e2e
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/coreos/etcd/clientv3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCtlV3AuthEnable(t *testing.T) { testCtl(t, authEnableTest) }
|
func TestCtlV3AuthEnable(t *testing.T) { testCtl(t, authEnableTest) }
|
||||||
@ -26,6 +28,7 @@ func TestCtlV3AuthRoleUpdate(t *testing.T) { testCtl(t, authRoleUpdateT
|
|||||||
func TestCtlV3AuthUserDeleteDuringOps(t *testing.T) { testCtl(t, authUserDeleteDuringOpsTest) }
|
func TestCtlV3AuthUserDeleteDuringOps(t *testing.T) { testCtl(t, authUserDeleteDuringOpsTest) }
|
||||||
func TestCtlV3AuthRoleRevokeDuringOps(t *testing.T) { testCtl(t, authRoleRevokeDuringOpsTest) }
|
func TestCtlV3AuthRoleRevokeDuringOps(t *testing.T) { testCtl(t, authRoleRevokeDuringOpsTest) }
|
||||||
func TestCtlV3AuthTxn(t *testing.T) { testCtl(t, authTestTxn) }
|
func TestCtlV3AuthTxn(t *testing.T) { testCtl(t, authTestTxn) }
|
||||||
|
func TestCtlV3AuthPerfixPerm(t *testing.T) { testCtl(t, authTestPrefixPerm) }
|
||||||
|
|
||||||
func authEnableTest(cx ctlCtx) {
|
func authEnableTest(cx ctlCtx) {
|
||||||
if err := authEnable(cx); err != nil {
|
if err := authEnable(cx); err != nil {
|
||||||
@ -172,7 +175,7 @@ func authRoleUpdateTest(cx ctlCtx) {
|
|||||||
|
|
||||||
// grant a new key
|
// grant a new key
|
||||||
cx.user, cx.pass = "root", "root"
|
cx.user, cx.pass = "root", "root"
|
||||||
if err := ctlV3RoleGrantPermission(cx, "test-role", grantingPerm{true, true, "hoo", ""}); err != nil {
|
if err := ctlV3RoleGrantPermission(cx, "test-role", grantingPerm{true, true, "hoo", "", false}); err != nil {
|
||||||
cx.t.Fatal(err)
|
cx.t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,7 +271,7 @@ func authRoleRevokeDuringOpsTest(cx ctlCtx) {
|
|||||||
cx.t.Fatal(err)
|
cx.t.Fatal(err)
|
||||||
}
|
}
|
||||||
// grant a new key to the new role
|
// grant a new key to the new role
|
||||||
if err := ctlV3RoleGrantPermission(cx, "test-role2", grantingPerm{true, true, "hoo", ""}); err != nil {
|
if err := ctlV3RoleGrantPermission(cx, "test-role2", grantingPerm{true, true, "hoo", "", false}); err != nil {
|
||||||
cx.t.Fatal(err)
|
cx.t.Fatal(err)
|
||||||
}
|
}
|
||||||
// grant the new role to the user
|
// grant the new role to the user
|
||||||
@ -370,7 +373,7 @@ func authTestTxn(cx ctlCtx) {
|
|||||||
// grant keys to test-user
|
// grant keys to test-user
|
||||||
cx.user, cx.pass = "root", "root"
|
cx.user, cx.pass = "root", "root"
|
||||||
for _, key := range grantedKeys {
|
for _, key := range grantedKeys {
|
||||||
if err := ctlV3RoleGrantPermission(cx, "test-role", grantingPerm{true, true, key, ""}); err != nil {
|
if err := ctlV3RoleGrantPermission(cx, "test-role", grantingPerm{true, true, key, "", false}); err != nil {
|
||||||
cx.t.Fatal(err)
|
cx.t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -422,3 +425,32 @@ func authTestTxn(cx ctlCtx) {
|
|||||||
cx.t.Fatal(err)
|
cx.t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func authTestPrefixPerm(cx ctlCtx) {
|
||||||
|
if err := authEnable(cx); err != nil {
|
||||||
|
cx.t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cx.user, cx.pass = "root", "root"
|
||||||
|
authSetupTestUser(cx)
|
||||||
|
|
||||||
|
prefix := "/prefix/" // directory like prefix
|
||||||
|
// grant keys to test-user
|
||||||
|
cx.user, cx.pass = "root", "root"
|
||||||
|
if err := ctlV3RoleGrantPermission(cx, "test-role", grantingPerm{true, true, prefix, "", true}); err != nil {
|
||||||
|
cx.t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// try a prefix granted permission
|
||||||
|
cx.user, cx.pass = "test-user", "pass"
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
key := fmt.Sprintf("%s%d", prefix, i)
|
||||||
|
if err := ctlV3Put(cx, key, "val", ""); err != nil {
|
||||||
|
cx.t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ctlV3PutFailPerm(cx, clientv3.GetPrefixRangeEnd(prefix), "baz"); err != nil {
|
||||||
|
cx.t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -101,6 +101,9 @@ func ctlV3Role(cx ctlCtx, args []string, expStr string) error {
|
|||||||
|
|
||||||
func ctlV3RoleGrantPermission(cx ctlCtx, rolename string, perm grantingPerm) error {
|
func ctlV3RoleGrantPermission(cx ctlCtx, rolename string, perm grantingPerm) error {
|
||||||
cmdArgs := append(cx.PrefixArgs(), "role", "grant-permission")
|
cmdArgs := append(cx.PrefixArgs(), "role", "grant-permission")
|
||||||
|
if perm.prefix {
|
||||||
|
cmdArgs = append(cmdArgs, "--prefix")
|
||||||
|
}
|
||||||
cmdArgs = append(cmdArgs, rolename)
|
cmdArgs = append(cmdArgs, rolename)
|
||||||
cmdArgs = append(cmdArgs, grantingPermToArgs(perm)...)
|
cmdArgs = append(cmdArgs, grantingPermToArgs(perm)...)
|
||||||
|
|
||||||
@ -137,6 +140,7 @@ type grantingPerm struct {
|
|||||||
write bool
|
write bool
|
||||||
key string
|
key string
|
||||||
rangeEnd string
|
rangeEnd string
|
||||||
|
prefix bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func grantingPermToArgs(perm grantingPerm) []string {
|
func grantingPermToArgs(perm grantingPerm) []string {
|
||||||
|
@ -22,6 +22,10 @@ import (
|
|||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
grantPermissionPrefix bool
|
||||||
|
)
|
||||||
|
|
||||||
// NewRoleCommand returns the cobra command for "role".
|
// NewRoleCommand returns the cobra command for "role".
|
||||||
func NewRoleCommand() *cobra.Command {
|
func NewRoleCommand() *cobra.Command {
|
||||||
ac := &cobra.Command{
|
ac := &cobra.Command{
|
||||||
@ -72,11 +76,15 @@ func newRoleListCommand() *cobra.Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newRoleGrantPermissionCommand() *cobra.Command {
|
func newRoleGrantPermissionCommand() *cobra.Command {
|
||||||
return &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "grant-permission <role name> <permission type> <key> [endkey]",
|
Use: "grant-permission <role name> <permission type> <key> [endkey]",
|
||||||
Short: "Grants a key to a role",
|
Short: "Grants a key to a role",
|
||||||
Run: roleGrantPermissionCommandFunc,
|
Run: roleGrantPermissionCommandFunc,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cmd.Flags().BoolVar(&grantPermissionPrefix, "prefix", false, "grant a prefix permission")
|
||||||
|
|
||||||
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func newRoleRevokePermissionCommand() *cobra.Command {
|
func newRoleRevokePermissionCommand() *cobra.Command {
|
||||||
@ -183,7 +191,12 @@ func roleGrantPermissionCommandFunc(cmd *cobra.Command, args []string) {
|
|||||||
|
|
||||||
rangeEnd := ""
|
rangeEnd := ""
|
||||||
if 4 <= len(args) {
|
if 4 <= len(args) {
|
||||||
|
if grantPermissionPrefix {
|
||||||
|
ExitWithError(ExitBadArgs, fmt.Errorf("don't pass both of --prefix option and range end to grant permission command"))
|
||||||
|
}
|
||||||
rangeEnd = args[3]
|
rangeEnd = args[3]
|
||||||
|
} else if grantPermissionPrefix {
|
||||||
|
rangeEnd = clientv3.GetPrefixRangeEnd(args[2])
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = mustClientFromCmd(cmd).Auth.RoleGrantPermission(context.TODO(), args[0], args[2], rangeEnd, perm)
|
_, err = mustClientFromCmd(cmd).Auth.RoleGrantPermission(context.TODO(), args[0], args[2], rangeEnd, perm)
|
||||||
|
Reference in New Issue
Block a user