腾讯云云原生 etcd(Cloud Service for etcd)是基于 开源 etcd 针对云原生服务场景进行优化的 etcd 托管解决方案。具体介绍说明可以参考文档https://cloud.tencent.com/document/product/457/58176 。
云原生etcd默认提供2种访问,http和https的方式,https双向认证及鉴权,启用 HTTPS 的情况下,支持开启客户端证书认证。http没有鉴权,可以直接访问。
etcd还有一种访问方式,就是用户身份认证功能,但是云原生etcd没有提供这种配置方式,因为https默认就有证书认证了,不需要再额外配置认证了,所以我们这里基于http方式云原生etcd配置下身份认证,来给云原生etcd增加认证。
前提条件:
- 腾讯云http方式访问的etcd实例
- 配置了etcdctl的客户端机器
1. 创建root用户和角色
root用户拥有etcd的所有权限,且必须在激活身份认证之前就创建好. root用户的设计主要是出于管理的目的: 管理角色和普通用户. root用户必须具有root角色, 并且可以在etcd中进行任何修改。
# 添加root用户 # etcdctl --endpoints="http://172.16.10.41:2379" user add root Password of root: Type password of root again for confirmation: User root created
添加root角色
etcdctl --endpoints="http://172.16.10.41" role add root
Role root created
root角色绑定到root用户
etcdctl --endpoints="http://172.16.10.41" user grant-role root root
Role root is granted to user root
开启auth
etcdctl --endpoints="http://172.16.10.41" auth enable
Authentication Enabled
没有开启认证前,直接设置key是正常的
开启auth后,这里访问etcd默认就需要加认证了,不然会报错
# etcdctl --endpoints="http://172.16.10.41" put c d
{"level":"warn","ts":"2023-06-23T14:31:21.660+0800","caller":"clientv3/retry_interceptor.go:62","msg":"retrying of unary invoker failed","target":"endpoint://client-11049eed-9e44-417b-bfa8-0fdf8ff23e3d/172.16.10.41:2379","attempt":0,"error":"rpc error: code = InvalidArgument desc = etcdserver: user name is empty"}
Error: etcdserver: user name is empty
访问etcd的数据,需要加上--user来认证
2. 创建用户
这里我们创建一个子用户,用来测试,创建用户时需要提供一个密码,如果使用 --interactive=false选项,支持从标准输入提供,也可以使用 --new-user-password 选项提供。
# etcdctl --endpoints="http://172.16.10.41" --user root:123456 user add nwx --new-user-password 123456
User nwx created
如果用户不需要了,删除用户可以用如下命令删除。
# etcdctl --endpoints="http://172.16.10.41" --user root:123456 user delete 用户名
3. 创建角色
接下来我们创建下角色,这里我们创建了3个角色,这里etcd角色可以被赋予3种权限,分别是read(读)、write(写)、readwrite(读和写)权限,这里3个角色分别对应不同的权限。
# etcdctl --endpoints="http://172.16.10.41" --user root:123456 role add etcd-ro
Role etcd-ro createdetcdctl --endpoints="http://172.16.10.41" --user root:123456 role add etcd-wo
Role etcd-wo created
etcdctl --endpoints="http://172.16.10.41" --user root:123456 role add etcd-wr
Role etcd-wr created
如果角色不需要了,删除角色可以用如下命令删除。
# etcdctl --endpoints="http://172.16.10.41" --user root:123456 role delete 角色名
4. 给角色授权
角色创建好之后,给角色授权下
- etcd-ro授予读权限
- etcd-wo授予写权限
- etcd-wr授予读写权限
角色授权是基于具体的key的,首先我们创建2个key,分别是test1和test2来用于测试
# etcdctl --endpoints="http://172.16.10.41" --user root:123456 put /test1 hello1
OKetcdctl --endpoints="http://172.16.10.41" --user root:123456 put /test2 hello2
OK
下面我们分别给角色分配test1这个key的权限
# etcdctl --endpoints="http://172.16.10.41" --user root:123456 role grant-permission etcd-ro read /test1
Role etcd-ro updatedetcdctl --endpoints="http://172.16.10.41" --user root:123456 role grant-permission etcd-wo write /test1
Role etcd-wo updated
etcdctl --endpoints="http://172.16.10.41" --user root:123456 role grant-permission etcd-wr readwrite /test1
Role etcd-wr updated
上面是设置单个key,如果要设置多个key,可以参考grant-permission的用法说明
# etcdctl role grant-permission --help
NAME:
role grant-permission - Grants a key to a role
USAGE:
etcdctl role grant-permission [options] <role name> <permission type> <key> [endkey] [flags]
OPTIONS:
--from-key[=false] grant a permission of keys that are greater than or equal to the given key using byte compare
-h, --help[=false] help for grant-permission
--prefix[=false] grant a prefix permission给以/foo/开头的所有key赋予读权限. The prefix is equal to the range [/foo/, /foo0)
etcdctl role grant-permission 角色名 --prefix=true read /foo/
给[key1, key5) 范围内的所有key赋予所有权限
etcdctl role grant-permission 角色名 readwrite key1 key5
赋予以/pub/可有的key所有权限
etcdctl role grant-permission 角色名 --prefix=true readwrite /pub/
如果需要给角色删除权限,可以用如下命令删除
# etcdctl --endpoints="http://172.16.10.41" --user root:123456 role revoke-permission 角色名 key
5. 给用户绑定角色测试权限
用户和角色都创建好了,我们给第一步创建的用户nwx绑定具体的角色来测试下权限是否生效。
给用户绑定和解除角色的命令如下
为用户添加角色
etcdctl user grant-role 用户名 角色名
为用户删除角色
etcdctl user revoke-role 用户名 角色名
5.1 用户绑定读权限的角色
这里首先给nwx绑定下etcd-ro角色,因为etcd-ro默认是分配的读权限
# etcdctl --endpoints="http://172.16.10.41" --user root:123456 user grant-role nwx etcd-ro
Role etcd-ro is granted to user nwxetcdctl --endpoints="http://172.16.10.41" --user root:123456 user get nwx
User: nwx
Roles: etcd-ro
然后我们测试下访问test1和test2这2个key试试,正常只能读test1这个key,其他key权限都没有
# etcdctl --endpoints="http://172.16.10.41" --user nwx:123456 get /test1
/test1
hello1etcdctl --endpoints="http://172.16.10.41" --user nwx:123456 put /test1 hello1-1
{"level":"warn","ts":"2023-06-23T14:56:21.693+0800","caller":"clientv3/retry_interceptor.go:62","msg":"retrying of unary invoker failed","target":"endpoint://client-8d09a8b1-1a12-41f7-be25-aecc4909adba/172.16.10.41:2379","attempt":0,"error":"rpc error: code = PermissionDenied desc = etcdserver: permission denied"}
Error: etcdserver: permission deniedetcdctl --endpoints="http://172.16.10.41" --user nwx:123456 get /test2
{"level":"warn","ts":"2023-06-23T14:56:33.235+0800","caller":"clientv3/retry_interceptor.go:62","msg":"retrying of unary invoker failed","target":"endpoint://client-47eb949b-240d-4e9c-9179-b540c7e99732/172.16.10.41:2379","attempt":0,"error":"rpc error: code = PermissionDenied desc = etcdserver: permission denied"}
Error: etcdserver: permission deniedetcdctl --endpoints="http://172.16.10.41" --user nwx:123456 put /test2 hello2-1
{"level":"warn","ts":"2023-06-23T14:56:47.108+0800","caller":"clientv3/retry_interceptor.go:62","msg":"retrying of unary invoker failed","target":"endpoint://client-255ca16f-47bc-4ded-ba79-0f6ede414778/172.16.10.41:2379","attempt":0,"error":"rpc error: code = PermissionDenied desc = etcdserver: permission denied"}
Error: etcdserver: permission denied
从测试结果看是符合角色权限设置预期的,只能读test1这个key。
5.2 用户绑定写权限的角色
这里继续测试下写权限的角色,我么给nwx绑定下etcd-wo角色,因为etcd-wo默认是分配的写权限,需要将etcd-ro的角色解绑掉,避免影响测试结果。
# etcdctl --endpoints="http://172.16.10.41" --user root:123456 user grant-role nwx etcd-wo
Role etcd-wo is granted to user nwxetcdctl --endpoints="http://172.16.10.41" --user root:123456 user revoke-role nwx etcd-ro
Role etcd-ro is revoked from user nwx
etcdctl --endpoints="http://172.16.10.41" --user root:123456 user get nwx
User: nwx
Roles: etcd-wo
然后我们测试下访问test1和test2这2个key试试,正常只能写test1这个key,其他key权限都没有。
# etcdctl --endpoints="http://172.16.10.41" --user nwx:123456 get /test1
{"level":"warn","ts":"2023-06-23T15:03:43.460+0800","caller":"clientv3/retry_interceptor.go:62","msg":"retrying of unary invoker failed","target":"endpoint://client-353c2a2e-7f00-4412-b373-17bb98968f41/172.16.10.41:2379","attempt":0,"error":"rpc error: code = PermissionDenied desc = etcdserver: permission denied"}
Error: etcdserver: permission deniedetcdctl --endpoints="http://172.16.10.41" --user nwx:123456 put /test1 hello1-1
OK
etcdctl --endpoints="http://172.16.10.41" --user nwx:123456 get /test2
{"level":"warn","ts":"2023-06-23T15:04:02.877+0800","caller":"clientv3/retry_interceptor.go:62","msg":"retrying of unary invoker failed","target":"endpoint://client-2044c10e-d752-4a3e-b40f-cffb29fe405d/172.16.10.41:2379","attempt":0,"error":"rpc error: code = PermissionDenied desc = etcdserver: permission denied"}
Error: etcdserver: permission deniedetcdctl --endpoints="http://172.16.10.41" --user nwx:123456 put /test2 hello2-1
{"level":"warn","ts":"2023-06-23T15:04:15.619+0800","caller":"clientv3/retry_interceptor.go:62","msg":"retrying of unary invoker failed","target":"endpoint://client-6a99f67d-b243-4d49-ac70-13b2dca8d0b5/172.16.10.41:2379","attempt":0,"error":"rpc error: code = PermissionDenied desc = etcdserver: permission denied"}
Error: etcdserver: permission denied
从测试结果看是符合角色权限设置预期的,只能写test1这个key。
5.3 用户绑定读写权限的角色
这里测试下读写权限的角色,我么给nwx绑定下etcd-wr角色,因为etcd-wr默认是分配的读写权限,需要将etcd-wo的角色解绑掉,避免影响测试结果。
# etcdctl --endpoints="http://172.16.10.41" --user root:123456 user revoke-role nwx etcd-wo
Role etcd-wo is revoked from user nwxetcdctl --endpoints="http://172.16.10.41" --user root:123456 user grant-role nwx etcd-wr
Role etcd-wr is granted to user nwx
etcdctl --endpoints="http://172.16.10.41" --user root:123456 user get nwx
User: nwx
Roles: etcd-wr
然后我们测试下访问test1和test2这2个key试试,正常只能读写test1这个key,其他key的权限都没有。
# etcdctl --endpoints="http://172.16.10.41" --user nwx:123456 get /test1
/test1
hello1-1etcdctl --endpoints="http://172.16.10.41" --user nwx:123456 put /test1 hello1
OK
etcdctl --endpoints="http://172.16.10.41" --user nwx:123456 get /test2
{"level":"warn","ts":"2023-06-23T15:08:54.681+0800","caller":"clientv3/retry_interceptor.go:62","msg":"retrying of unary invoker failed","target":"endpoint://client-9da01b24-df4e-4d5c-bebb-37de9d9571e7/172.16.10.41:2379","attempt":0,"error":"rpc error: code = PermissionDenied desc = etcdserver: permission denied"}
Error: etcdserver: permission deniedetcdctl --endpoints="http://172.16.10.41" --user nwx:123456 put /test2 hello2-1
{"level":"warn","ts":"2023-06-23T15:09:03.869+0800","caller":"clientv3/retry_interceptor.go:62","msg":"retrying of unary invoker failed","target":"endpoint://client-c2691c6e-39d6-4686-83f2-cf1b09d8e3b1/172.16.10.41:2379","attempt":0,"error":"rpc error: code = PermissionDenied desc = etcdserver: permission denied"}
Error: etcdserver: permission denied
从测试结果看是符合角色权限设置预期的,可以读写test1这个key,其他key的权限都没,并且这里查看test1的值是hello1-1,也验证了上一步的测试,给分配读权限是正常的。
上面就是如何通过用户和角色来控制权限,通过用户和角色可以更加灵活的来控制etcd里面的数据访问。