天天看点

《ZooKeeper官方指南》ZooKeeper 使用 ACL 进行访问控制

原文链接 译者:thor_liu

zookeeper 使用 acl 进行访问控制

zookeeper使用acl来控制访问其znode(zookeeper的数据树的数据节点)。acl的实现方式非常类似于unix文件的访问权限:它采用访问权限位 允许/禁止 对节点的各种操作以及能进行操作的范围。不同于unix权限的是,zookeeper的节点不局限于 用户(文件的拥有者),组和其他人(其它)这三个标准范围。zookeeper不具有znode的拥有者的概念。相反,acl指定id集以及与之对应的权限。

还要注意的是一条acl仅针对于一个特定的节点。尤其不适用于子节点。例如,如果/app 只对ip:172.16.16.1可读 而 / app/status 是对任何人可读的,acl不是递归的。

zookeeper支持可插拔的身份验证方案。 id使用如下形式  scheme:id,其中 scheme 是 id 所对应一个认证方案。例如,ip:172.16.16.1,id为主机的地址 172.16.16.1。

当客户端连接到zookeeper验证自己时,zookeeper将有关该客户端的所有id与客户连接关联。客户端试图访问一个节点时,这些id与该znodes的acl验证。 acl是由(scheme:expression, perms)对构成。其中expression的格式指定为scheme。例如,(ip:19.22.0.0/16,read)表示对所有起始ip为19.22的客户端具有读权限。

acl 权限

zookeeper 支持以下权限:

create: 能创建子节点

read:能获取节点数据和列出其子节点

write: 能设置节点数据

delete: 能删除子节点

admin: 能设置权限

create权限和delete权限从write权限中分离出来,是为了获得更好的访问控制。使用create和delete权限的场景如下:

你想让a用户能够设置节点数据,但不允许创建或删除子节点。

有create但无delete权限:客户端发出一个在父目录下创建节点的请求。你想让所有客户端能够添加,但是只有创建者能够删除。(这类似于文件的append权限)。

内置的 acl schemes

zookeeper有如下内置的schemes

world 有个唯一的id, anyone ,代表所有人。

auth 不使用任何id,代表任何已认证的用户。

digest 用 username:password 字符串来产生一个md5串,然后该串被用来作为acl id。认证是通过明文发送username:password 来进行的,当用在acl时,表达式为username:base64 ,base64是password的sha1摘要的编码。

ip 使用客户端的主机ip作为acl id 。这个acl表达式的格式为addr/bits ,此时addr中的有效位与客户端addr中的有效位进行比对。

zookeeper c 客户端 api

如下的常量是由zookeeper c语言库中提供的:

const int zoo_perm_read;  //能读节点的值及列出其子节点

const int zoo_perm_write; //能设置节点的值

const int zoo_perm_create;  //能创建子节点

const int zoo_perm_delete; // 能删除子节点

const int zoo_perm_admin;  //能执行set_acl()

const int zoo_perm_all; // 上面所有值的or

struct id zoo_anyone_id_unsafe; //(‘world’,’anyone’)

struct id zoo_auth_ids;// (‘auth’,’’)

zoo_auth_ids 为空时,应被理解成“创建者的id”

zookeeper 客户端有3种标准的acl:

struct acl_vector zoo_open_acl_unsafe; //(zoo_perm_all,zoo_anyone_id_unsafe)

struct acl_vector zoo_read_acl_unsafe;// (zoo_perm_read, zoo_anyone_id_unsafe)

struct acl_vector zoo_creator_all_acl; //(zoo_perm_all,zoo_auth_ids)

zoo_open_acl_unsafe使所有acl都“开放”了:任何应用程序在节点上可进行任何操作,能创建、列出和删除它的子节点。对任何应用程序,zoo_read_acl_unsafe是只读的。create_all_acl赋予了节点的创建者所有的权限,在创建者采用此acl创建节点之前,已经被服务器所认证(例如,采用 “ digest”方案)。

以下zookeeper方法处理acl:

int zoo_add_auth (zhandle_t *zh,const char* scheme,const char* cert, int certlen, void_completion_t completion, const void *data);

the application uses the zoo_add_auth function to authenticate itself to the server. the function can be called multiple times if the application wants to authenticate using different schemes and/or identities.

应用程序使用zoo_add_auth方法来向服务器认证自己,如果想用不同的方案来认证,这个方法可以被调用多次。

int zoo_create (zhandle_t *zh, const char *path, const char *value,int valuelen, const struct acl_vector *acl, int flags,char *realpath, int max_realpath_len);

zoo_create(…)方法创建一个新节点。acl 参数是一个与这个节点关联的acl列表,父节点权限项的create位已被设(set,即由权限)。

int zoo_get_acl (zhandle_t *zh, const char *path,struct acl_vector *acl, struct stat *stat);

这个方法返回这个节点的acl信息。

int zoo_set_acl (zhandle_t *zh, const char *path, int version,const struct acl_vector *acl);

这个方法用新的节点的acl列表替换老的,这个节点的admin位必须被设置(set,即具有admin权限)。

这有一个使用上面api的例子,采用”foo”方案认证,创建一个“/xyz”的暂态节点,设置其为”只创建“权限。

这是一个非常简单的例子,它的目的是展示如何与zookeeper acl交换。c客户端的实现,参考…/trunk/src/c/src/cli.c .

#include <errno.h>

#include “zookeeper.h”

static zhandle_t *zh;

/**

* in this example this method gets the cert for your

* environment — you must provide

*/

char *foo_get_cert_once(char* id) { return 0; }

/** watcher function — empty for this example, not something you should

* do in real code */

void watcher(zhandle_t *zzh, int type, int state, const char *path,

void *watcherctx) {}

int main(int argc, char argv) {

char buffer[512];

char p[2048];

char *cert=0;

char appid[64];

strcpy(appid, “example.foo_test”);

cert = foo_get_cert_once(appid);

if(cert!=0) {

fprintf(stderr,

“certificate for appid [%s] is [%s]\n”,appid,cert);

strncpy(p,cert, sizeof(p)-1);

free(cert);

} else {

fprintf(stderr, “certificate for appid [%s] not found\n”,appid);

strcpy(p, “dummy”);

}

zoo_set_debug_level(zoo_log_level_debug);

zh = zookeeper_init(“localhost:3181″, watcher, 10000, 0, 0, 0);

if (!zh) {

return errno;

if(zoo_add_auth(zh,”foo”,p,strlen(p),0,0)!=zok)

return 2;

struct acl create_only_acl[] = {{zoo_perm_create, zoo_auth_ids}};

struct acl_vector create_only = {1, create_only_acl};

int rc = zoo_create(zh,”/xyz”,”value”, 5, &create_only, zoo_ephemeral,

buffer, sizeof(buffer)-1);

/** this operation will fail with a znoauth error */

int buflen= sizeof(buffer);

struct stat stat;

rc = zoo_get(zh, “/xyz”, 0, buffer, &buflen, &stat);

if (rc) {

fprintf(stderr, “error %d for %s\n”, rc, __line__);

zookeeper_close(zh);

return 0;

继续阅读