文章目录

  • ​​访问安全​​
  • ​​etcd权限分类​​
  • ​​etcd 访问控制​​
  • ​​传输安全​​
  • ​​生成证书​​
  • ​​配置使用证书​​
  • ​​问题处理​​

访问安全

在 2.1 版本之前, etcd 是 一个完全开放的系统,任何用户都可以通过 REST API 修改 etcd 存储的数据。 etcd 在 2.1 版本中增加了用户( User )和角色( Role )的概念,引入了用户认证的功能 。 为了保持向后兼容性和可升级性, etcd 的用户权限功能默认是关闭的 。 etcd 支持安全认证以及权限管理。 etcd 的权限管理借鉴了操作系统的权限管理思想,存在 用户和角色(分组)两种权限管理方法 。

etcd权限分类

etcd 包含三种类型的资源,具体如下:
权限资源( permission resources ):
用户(User )和角色( Role )信息 。

root 用户拥有对 etcd 访问的全部权限,并且必须在启动认证之前预先创,否则会无法启用身份认证功能。 root 用户具有 root 角色功能 并允许对 etcd 内部进行任何操作。

在 etcd 中,角色主要 分三类: root 角色、 guest 角色和普通角色 。 etcd 默认创建 root 用户时即创建了 root 角色,并为其绑定了该角色, 该角色不能被修改,root 角色可以授予任何用户 , 一旦某个用户被授予了 root 角色,它就拥有全局的读写权限以及修改集群认证配置的权限 。

guest 角色也会被自动创建 。 guest 角色针对未经身份验证的请求提供访问 etcd 的权限,如果访问etcd时没有指定任何验证方式和用户(未启用auth 也没输入用户名密码时) ,那么请求方默认会被设定为 guest 角色 。 默认情况下, etcd 的 guest 角色具有对 etcd 所有键值资源的全局访问权限。为了减少未经授权的用户的能力,可以根据需要修改、撤销,甚至是删除该角 色。

提供了两种类型的权限( permission ):读和写 。 对权限的所有管理和 设置都需要通过 root 角色来实现

键值资源( key-value resources ):
指存储在 etcd 中的键值对信息。可以设定一个用于匹配的模式 (pattern )列表
/foo 表示一个精确的 key 值或目录,那么只能为该 key 值或目 录授予权限, 而不能为它的子节点授予权限
/foo* 表示所有以 foo 开头 的 key 值或目录都具有该权限(例如“/foobar ”,注意“/foo*”与“/foo/*”的 区别)
*表示具有所有键值资源的权限

配置资源( settings resources ):
安全配置信息 、 权限配置信息和 etcd 集 群动态配置信息(选举/心跳等 )

etcd 访问控制

V2API操作如下:

etc user list  --查看用户列表
etc user add saguser 添加用户 需要输入密码
etc user list --查看用户
etc role list --查看角色列表
etc role add sagrole 添加角色
etc role grant sagrole --path /userinfo/* --readwrite 未角色添加权限
etc role get sagrole 查看角色信息
etc role revoke sagrole --path /userinfo/* --readwrite 取消角色权限
etc user grant --help 帮助信息
etc user grant root --roles root 未用户添加角色
etc user passwd saguser --重置用户密码
etc auth enable 开启etcd 权限验证

V3API操作

etc  user add saguser --添加用户
etc user add root --添加用户
etc user list --查看列表
etc role list --查看列表
etc role add sagrole --添加角色
etc role grant-permission --help --查看赋权限帮助信息
etc role grant-permission --prefix=true sagrole readwrite /userinfo/ --为角色配置权限
etc role get sagrole --查看角色信息
etc auth enable --开启权限验证

etc --user root:root role get sagrole
etc --user saguser:saguser put /userinfo/test zhangsan --提示无权限
etc --user root:root put /userinfo/test zhangsan --可以正常写入
etc --user saguser:saguser role get /userinfo/test --提示无权限
etc --user root:root user grant-role saguser sagrole --为用户saguser 添加 sagrole角色
etc --user saguser:saguser role get /userinfo/test -- 写入数据正常
etc --user saguser:saguser get /userinfo/test --读取数据正常

etc --user saguser:saguser put /userinfo1/test2 lisi --读写其他未授权的键值还是提示没有权限
Error: etcdserver: permission denied

传输安全

etcd 支持 TLS 协议加密通信。TLS通道既能用于加密 etcd 集群内部通信,也能加密客户端与服务端的通信。

生成证书

下载cfssl

wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64
wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64
wget https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64
chmod -x cfssl* --添加执行权限
for x in cfssl*; do mv $x ${x%*_linux-amd64}; done --去掉命令后缀

etcd 需要如下三类证书
client certificate :用于通过服务器验证客户端。 例如, etcdctLetcd proxy 等 。
server certificate :由服务器使用,用于通过客户端验证服务器身份。 例 如, etcd 服务器。
peer certificate :由 etcd 集群成员使用,用于加密它们之间的通信 。
初始化CA配置
创建ca配置文件 ca-config如下

{
"signing": {
"default": {
"expiry": "43800h"
},
"profiles": {
"server": {
"expiry": "43800h",
"usages": [
"signing",
"key encipherment",
"server auth",
"client auth"
]
},
"client": {
"expiry": "43800h",
"usages": [
"signing",
"key encipherment",
"client auth"
]
},
"peer": {
"expiry": "43800h",
"usages": [
"signing",
"key encipherment",
"server auth",
"client auth"
]
}
}
}
}

配置文件ca-csr 如下

{
"CN":"MyCa",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "shanghai",
"O": "cfssl",
"ST": "shanghai",
"OU": "System"
}
]
}

生成根证书

./cfssl gencert -initca ca-csr | ./cfssljson -bare ca -
-rw-r--r--. 1 root root 997 11月 15 23:33 ca.csr
-rw-------. 1 root root 1675 11月 15 23:33 ca-key.pem
-rw-r--r--. 1 root root 1354 11月 15 23:33 ca.pe

生成server证书

echo '{"CN":"server","hosts":["192.168.90.23","127.0.0.1"],"key":{"algo":"rsa","size":2048}}' | ./cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config='ca-config' -profile=server -hostname="192.168.90.23,127.0.0.1" - | ./cfssljson -bare server

生成成员证书
这里集群包含三个节点如下

name: node1
data-dir: /root/etcluster/etc1/data
wal-dir: /root/etcluster/etc1/data/wal
listen-peer-urls: http://192.168.90.23:2380
listen-client-urls: http://192.168.90.23:2379,http://127.0.0.1:2379
advertise-client-urls: http://192.168.90.23:2379
snapshot-count: 5
initial-advertise-peer-urls: http://192.168.90.23:2380
initial-cluster: node1=http://192.168.90.23:2380,node2=http://1192.168.90.23:2480,node3=http://192.168.90.23:2580
initial-cluster-state: new
initial-cluster-token: etcluster

name: node2
data-dir: /root/etcluster/etc2/data
wal-dir: /root/etcluster/etc2/data/wal
listen-peer-urls: http://192.168.90.23:2480
initial-advertise-peer-urls: http://192.168.90.23:2480
listen-client-urls: http://192.168.90.23:2479,http://127.0.0.1:2479
advertise-client-urls: http://192.168.90.23:2479
snapshot-count: 5
initial-cluster: node1=http://192.168.90.23:2380,node2=http://1192.168.90.23:2480,node3=http://192.168.90.23:2580
initial-cluster-state: new
initial-cluster-token: etcluster


name: node3
data-dir: /root/etcluster/etc3/data
wal-dir: /root/etcluster/etc3/data/wal
listen-peer-urls: http://192.168.90.23:2580
initial-advertise-peer-urls: http://192.168.90.23:2580
listen-client-urls: http://192.168.90.23:2579,http://127.0.0.1:2579
advertise-client-urls: http://192.168.90.23:2579
snapshot-count: 5
initial-cluster: node1=http://192.168.90.23:2380,node2=http://1192.168.90.23:2480,node3=http://192.168.90.23:2580
initial-cluster-state: new
initial-cluster-token: etcluster

执行如下命令 分别生成三个节点的证书

echo '{"CN":"node1","hosts":["192.168.90.23","127.0.0.1"],"key":{"algo":"rsa","size":2048}}' | ./cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config='ca-config' -profile=peer -hostname="192.168.90.23,127.0.0.1" - | ./cfssljson -bare node1

echo '{"CN":"node2","hosts":["192.168.90.23","127.0.0.1"],"key":{"algo":"rsa","size":2048}}' | ./cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config='ca-config' -profile=peer -hostname="192.168.90.23,127.0.0.1" - | ./cfssljson -bare node2

echo '{"CN":"node3","hosts":["192.168.90.23","127.0.0.1"],"key":{"algo":"rsa","size":2048}}' | ./cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config='ca-config' -profile=peer -hostname="192.168.90.23,127.0.0.1" - | ./cfssljson -bare node3

生成客户端证书
执行如下命令

echo '{"CN":"client","hosts":["192.168.90.23","127.0.0.1"],"key":{"algo":"rsa","size":2048}}' | ./cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config='ca-config' -profile=client  -hostname="192.168.90.23,127.0.0.1"   - | ./cfssljson -bare client

一共生成了这么多证书

-rw-r--r--. 1 root root      940 11月 16 23:18 client.csr
-rw-------. 1 root root 1675 11月 16 23:18 client-key.pem
-rw-r--r--. 1 root root 1298 11月 16 23:18 client.pem
drwxr-xr-x. 2 root root 6 11月 15 23:09 etcdcers
-rw-r--r--. 1 root root 940 11月 16 23:10 node1.csr
-rw-------. 1 root root 1679 11月 16 23:10 node1-key.pem
-rw-r--r--. 1 root root 1310 11月 16 23:10 node1.pem
-rw-r--r--. 1 root root 940 11月 16 23:11 node2.csr
-rw-------. 1 root root 1675 11月 16 23:11 node2-key.pem
-rw-r--r--. 1 root root 1310 11月 16 23:11 node2.pem
-rw-r--r--. 1 root root 940 11月 16 23:11 node3.csr
-rw-------. 1 root root 1679 11月 16 23:11 node3-key.pem
-rw-r--r--. 1 root root 1310 11月 16 23:11 node3.pem
-rw-r--r--. 1 root root 940 11月 16 23:47 server.csr
-rw-------. 1 root root 1675 11月 16 23:47 server-key.pem
-rw-r--r--. 1 root root 1298 11月 16 23:47 server.pem
-rw-r--r--. 1 root root 997 11月 15 23:33 ca.csr
-rw-------. 1 root root 1675 11月 15 23:33 ca-key.pem
-rw-r--r--. 1 root root 1354 11月 15 23:33 ca.pem

将生成的证书复制到指定的节点文件夹

[root@localhost cfssl]# cp node1* /root/etcluster/etc1
[root@localhost cfssl]# cp node2* /root/etcluster/etc2
[root@localhost cfssl]# cp node3* /root/etcluster/etc3
[root@localhost cfssl]# cp server* /root/etcluster/etc1
[root@localhost cfssl]# cp server* /root/etcluster/etc2
[root@localhost cfssl]# cp server* /root/etcluster/etc3
[root@localhost cfssl]# cp ca* /root/etcluster/etc1
[root@localhost cfssl]# cp ca* /root/etcluster/etc2
[root@localhost cfssl]# cp ca* /root/etcluster/etc3
[root@localhost cfssl]# cp client* /root/etcluster/etc3 client 也复制到node3目录

配置使用证书

etcd 提供了一些与安全通信相关的参数。通过以下参数,重新启动etcd服务

/root/etcluster/etc3/etcd \
--name node3 \
--data-dir /root/etcluster/etc3/data \
--wal-dir /root/etcluster/etc3/data/wal \
--listen-peer-urls https://192.168.90.23:2580 \
--initial-advertise-peer-urls https://192.168.90.23:2580 \
--listen-client-urls https://192.168.90.23:2579,https://127.0.0.1:2579 \
--advertise-client-urls http://192.168.90.23:2579 \
--initial-cluster node1=https://192.168.90.23:2380,node2=https://192.168.90.23:2480,node3=https://192.168.90.23:2580 \
--initial-cluster-state new \
--initial-cluster-token etcluster \
--client-cert-auth \
--trusted-ca-file /root/etcluster/etc3/ca.pem \
--cert-file /root/etcluster/etc3/server.pem \
--key-file /root/etcluster/etc3/server-key.pem \
--peer-client-cert-auth \
--peer-trusted-ca-file /root/etcluster/etc3/ca.pem \
--peer-cert-file /root/etcluster/etc3/node3.pem \
--peer-key-file /root/etcluster/etc3/node3-key.pem


/root/etcluster/etc2/etcd \
--name node2 \
--data-dir /root/etcluster/etc2/data \
--wal-dir /root/etcluster/etc2/data/wal \
--listen-peer-urls https://192.168.90.23:2480 \
--initial-advertise-peer-urls https://192.168.90.23:2480 \
--listen-client-urls https://192.168.90.23:2479,https://127.0.0.1:2479 \
--advertise-client-urls https://192.168.90.23:2479 \
--initial-cluster node1=https://192.168.90.23:2380,node2=https://192.168.90.23:2480,node3=https://192.168.90.23:2580 \
--initial-cluster-state new \
--initial-cluster-token etcluster \
--client-cert-auth \
--trusted-ca-file /root/etcluster/etc2/ca.pem \
--cert-file /root/etcluster/etc2/server.pem \
--key-file /root/etcluster/etc2/server-key.pem \
--peer-client-cert-auth \
--peer-trusted-ca-file /root/etcluster/etc2/ca.pem \
--peer-cert-file /root/etcluster/etc2/node2.pem \
--peer-key-file /root/etcluster/etc2/node2-key.pem



/root/etcluster/etc1/etcd \
--name node1 \
--data-dir /root/etcluster/etc1/data \
--wal-dir /root/etcluster/etc1/data/wal \
--listen-peer-urls https://192.168.90.23:2380 \
--initial-advertise-peer-urls https://192.168.90.23:2380 \
--listen-client-urls https://192.168.90.23:2379,https://127.0.0.1:2379 \
--advertise-client-urls https://192.168.90.23:2379 \
--initial-cluster node1=https://192.168.90.23:2380,node2=https://192.168.90.23:2480,node3=https://192.168.90.23:2580 \
--initial-cluster-state new \
--initial-cluster-token etcluster \
--client-cert-auth \
--trusted-ca-file /root/etcluster/etc1/ca.pem \
--cert-file /root/etcluster/etc1/server.pem \
--key-file /root/etcluster/etc1/server-key.pem \
--peer-client-cert-auth \
--peer-trusted-ca-file /root/etcluster/etc1/ca.pem \
--peer-cert-file /root/etcluster/etc1/node1.pem \
--peer-key-file /root/etcluster/etc1/node1-key.pem

etcdctl 使用证书访问

etc --cacert=/root/etcluster/etc3/ca.pem --cert=/root/etcluster/etc3/client.pem --key=/root/etcluster/etc3/client-key.pem put /test zhangsan

使用etcdctl 进行读写测试如下,必须使用客户端证书才能正常访问否则后端会报错 :

[root@localhost cfssl]# etc  put /test zhangsan
{"level":"warn","ts":"2021-11-17T23:30:49.309+0800","logger":"etcd-client","caller":"v3/retry_interceptor.go:62","msg":"retrying of unary invoker failed","target":"etcd-endpoints://0xc000318380/127.0.0.1:2379","attempt":0,"error":"rpc error: code = DeadlineExceeded desc = latest balancer error: last connection error: connection closed"}
Error: context deadline exceeded
[root@localhost cfssl]# etc --cacert=/root/etcluster/etc3/ca.pem --cert=/root/etcluster/etc3/client.pem --key=/root/etcluster/etc3/client-key.pem get /test
/test
zhangsan
[root@localhost cfssl]# etc --cacert=/root/etcluster/etc3/ca.pem --cert=/root/etcluster/etc3/client.pem --key=/root/etcluster/etc3/client-key.pem endpoint status
127.0.0.1:2379, 476ccb1849c690cf, 3.5.1, 20 kB, false, false, 3, 14, 14,
[root@localhost cfssl]# etc --cacert=/root/etcluster/etc3/ca.pem --cert=/root/etcluster/etc3/client.pem --key=/root/etcluster/etc3/client-key.pem --endpoints=https://192.168.90.23:2379,https://192.168.90.23:2479,https://192.168.90.23:2579 endpoint status
https://192.168.90.23:2379, 476ccb1849c690cf, 3.5.1, 20 kB, false, false, 3, 14, 14,
https://192.168.90.23:2479, 7a5d9ff142ed38b4, 3.5.1, 20 kB, false, false, 3, 14, 14,
https://192.168.90.23:2579, a72c8ee1679654d2, 3.5.1, 20 kB, true, false, 3, 14, 14,
[root@localhost cfssl]# etc --cacert=/root/etcluster/etc3/ca.pem --cert=/root/etcluster/etc3/client.pem --key=/root/etcluster/etc3/client-key.pem --endpoints=https://192.168.90.23:2379,https://192.168.90.23:2479,https://192.168.90.23:2579 --write-out=table endpoint status
+----------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |
+----------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| https://192.168.90.23:2379 | 476ccb1849c690cf | 3.5.1 | 20 kB | false | false | 3 | 14 | 14 | |
| https://192.168.90.23:2479 | 7a5d9ff142ed38b4 | 3.5.1 | 20 kB | false | false | 3 | 14 | 14 | |
| https://192.168.90.23:2579 | a72c8ee1679654d2 | 3.5.1 | 20 kB | true | false | 3 | 14 | 14 | |
+----------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+

不使用证书访问报错如下:

{"level":"warn","ts":"2021-11-17T23:30:45.308+0800","caller":"embed/config_logging.go:169","msg":"rejected connection","remote-addr":"127.0.0.1:48398","server-name":"","error":"tls: first record does not look like a TLS handshake"}
{"level":"warn","ts":"2021-11-17T23:30:47.056+0800","caller":"embed/config_logging.go:169","msg":"rejected connection","remote-addr":"127.0.0.1:48408","server-name":"","error":"tls: first record does not look like a TLS handshake"}

问题处理

第一次测试后报错如下:

2020-06-28 16:00:15.047099 I | embed: rejected connection from "127.0.0.1:42457" (error "tls: failed to verify client's certificate: x509: certificate specifies an incompatible key usage", ServerName "")
WARNING: 2020/06/28 16:00:15 grpc: addrConn.createTransport failed to connect to {0.0.0.0:5001 0 <nil>}. Err :connection error: desc = "transport: authentication handshake failed: remote error: tls: bad certificate". Reconnecting...

原因是,生成证书的ca-config文件缺少如下内容

etcd用户、角色及证书配置_etcd


补充内容后,重新生成替换server证书,并启动即可。