共计 3928 个字符,预计需要花费 10 分钟才能阅读完成。
前言
关于 zookeeper 知之甚少,少之又少,只是作为 dubbo 的注册中心连接,某天某检测机构随手一扫然后说你们 zookeeper 没有设置任何安全验证,当时就懵了,还有这种操作。
zookeeper 设置 ACL 权限
查阅 dubbo 的官方文档 dubbo-registry 发现连接注册中心的时候是可以选择是否需要用户名密码,接下来就是要如何设置 zookeeper 的用户名跟密码
进入 zookeeper 的 bin 文件夹运行客户端
./zkCli.sh
-help 查看指令
[zk: localhost:2181(CONNECTED) 0] -help
ZooKeeper -server host:port cmd args
stat path [watch]
set path data [version]
ls path [watch]
delquota [-n|-b] path
ls2 path [watch]
setAcl path acl
setquota -n|-b val path
history
redo cmdno
printwatches on|off
delete path [version]
sync path
listquota path
rmr path
get path [watch]
create [-s] [-e] path data acl
addauth scheme auth
quit
getAcl path
close
connect host:port
如果在 dubbo 中没有指定分组的话,dubbo 会默认生成一个分组 dubbo,也就是在 zookeeper 下面会有个子节点 dubbo
也可以自己手动创建
create /dubbo
Zookeeper 的 ACL 通过 scheme:id:permissions 来构成权限 scheme 这边主要用到 2 种方式,另外还有设置 ip 和 host, 这几个没用到的这边就先不细说
1.auth 方式(密码明文)添加用户名和密码
addauth digest onepay:onepay
授予 /dubbo auth 权限
setAcl /dubbo auth:onepay:onepay:rwadc
配置 dubbo 连接 zookeeper 配置文件
<dubbo:registry protocol =”zookeeper” address=”127.0.0.1:2181″ username=”onepay” password=”onepay” client=”curator” />
2.digest 授权方式(方式跟 auth 差不多)授予 /dubbo digest 权限
setAcl /dubbo digest:onepay:T+17ezPAW0kDvN6elPD5Tdzdm00=:cdrwa
addauth digest onepay:onepay
配置 zookeeper 配置文件
<dubbo:registry protocol =”zookeeper” address=”127.0.0.1:2181″ username=”onepay” password=”onepay” client=”curator” />
digest 密码生成方式: 把密码进行 sha1 编码然后对结果进行 base64 编码
BASE64(SHA1(password))
查看 zookeeper 源码发现,其实包里面已经有现成的方法, 直接调用这个类生成就行,idPassword 字符串格式: username:passwordorg.apache.zookeeper.server.auth.DigestAuthenticationProvider
static public String generateDigest(String idPassword)
throws NoSuchAlgorithmException {
String parts[] = idPassword.split(“:”, 2);
byte digest[] = MessageDigest.getInstance(“SHA1”).digest(
idPassword.getBytes());
return parts[0] + “:” + base64Encode(digest);
}
还有一个点就是要设置 client=”curator” 通过 ZookeeperRegistry 发现 zookeeper 的连接是通过 zookeeperTransporter 进行创建,zookeeperTransporter 接口分别由 CuratorZookeeperTransporterZkclientZookeeperTransporter 实现,这 2 个分别创建 CuratorZookeeperClient 和 ZkclientZookeeperClient
public class ZkclientZookeeperTransporter implements ZookeeperTransporter {
public ZookeeperClient connect(URL url) {
return new ZkclientZookeeperClient(url);
}
}
public class CuratorZookeeperTransporter implements ZookeeperTransporter {
public ZookeeperClient connect(URL url) {
return new CuratorZookeeperClient(url);
}
}
查看源码发现 ZkclientZookeeperClient 是没有进行设置 zookeeper 的 auth 的账号和密码,CuratorZookeeperClient 有去获取配置的相关用户信息。
public ZkclientZookeeperClient(URL url) {
super(url);
client = new ZkClient(url.getBackupAddress());
client.subscribeStateChanges(new IZkStateListener() {
public void handleStateChanged(KeeperState state) throws Exception {
ZkclientZookeeperClient.this.state = state;
if (state == KeeperState.Disconnected) {
stateChanged(StateListener.DISCONNECTED);
} else if (state == KeeperState.SyncConnected) {
stateChanged(StateListener.CONNECTED);
}
}
public void handleNewSession() throws Exception {
stateChanged(StateListener.RECONNECTED);
}
});
}
public CuratorZookeeperClient(URL url) {
super(url);
try {
Builder builder = CuratorFrameworkFactory.builder()
.connectString(url.getBackupAddress())
.retryPolicy(new RetryNTimes(Integer.MAX_VALUE, 1000))
.connectionTimeoutMs(5000);
String authority = url.getAuthority();
if (authority != null && authority.length() > 0) {
builder = builder.authorization(“digest”, authority.getBytes());
}
client = builder.build();
client.getConnectionStateListenable().addListener(new ConnectionStateListener() {
public void stateChanged(CuratorFramework client, ConnectionState state) {
if (state == ConnectionState.LOST) {
CuratorZookeeperClient.this.stateChanged(StateListener.DISCONNECTED);
} else if (state == ConnectionState.CONNECTED) {
CuratorZookeeperClient.this.stateChanged(StateListener.CONNECTED);
} else if (state == ConnectionState.RECONNECTED) {
CuratorZookeeperClient.this.stateChanged(StateListener.RECONNECTED);
}
}
});
client.start();
} catch (IOException e) {
throw new IllegalStateException(e.getMessage(), e);
}
}
cdrwa 表示 zookeeper 的五种权限
CREATE: 创建子节点 READ: 获取节点数据或者当前节点的子节点列表 WRITE: 节点设置数据 DELETE: 删除子节点 ADMIN: 节点设置权限
如果用户名密码错误,或者没设置,会报 KeeperErrorCode = NoAuth 错误
注:停止 zookeeper,清除 zookeeper 文件夹下面的 logs,或者用 delete 删除节点 就可以清除权限
以上参考文档 Apache Zookeeper Setting ACL