跳转到主要内容

基于角色的访问控制

一个基于角色的基本身份认证和访问控制指南

概述

身份认证功能自 etcd 2.1 版本起引入。etcd v3 API 对身份认证功能的 API 和用户界面进行了轻微调整,以更好地适配新的数据模型。本文旨在帮助用户在 etcd v3 中设置基本的身份认证和基于角色的访问控制。

特殊用户和角色

有一个特殊用户 root,以及一个特殊角色 root。

用户 root

root 用户在激活身份认证前必须先创建,该用户拥有对 etcd 的完全访问权限。root 用户的设计初衷是用于系统管理:管理角色和普通用户。root 用户必须拥有 root 角色,并被允许修改 etcd 内的任意内容。

角色 root

角色 root 可授予任意用户,包括根用户。拥有 root 角色的用户具备全局读写权限,并可更新集群的身份认证配置。此外,root 角色授予用户执行常规集群维护的权限,包括修改集群成员关系、整理碎片以及创建快照。

使用用户

user 子命令用于 etcdctl,负责处理与用户账户相关的所有事项。

用户列表可通过以下方式获取:

$ etcdctl user list

创建用户的方法如下:

$ etcdctl user add myusername

创建新用户时将提示输入新密码。当提供选项 --interactive=false 时,可从标准输入提供密码。也可使用 --new-user-password 来提供密码。

创建无法通过密码认证的用户也是可行的,方法如下:

$ etcdctl user add myusername --no-password

此类用户只能通过 TLS 通用名称 进行认证 。

说明

etcd 不支持通过 --user username: 使用空密码进行身份认证。例如,使用空密码创建的用户,如 etcdctl user add anonymous:'',无法通过用户名/密码请求进行身份认证,类似 etcdctl --user anonymous: get foo 的请求将失败并返回 user name is empty。

用户的角色可使用以下方式授予或撤销:

$ etcdctl user grant-role myusername foo
$ etcdctl user revoke-role myusername bar

用户设置可通过以下方式检查:

$ etcdctl user get myusername

用户密码可通过以下方式更改:

$ etcdctl user passwd myusername

更改密码后,将再次提示输入新密码。当提供选项 --interactive=false 时,密码可从标准输入提供。

使用以下命令删除账户:

$ etcdctl user delete myusername

使用角色

role 子命令用于 etcdctl,负责处理与特定角色访问控制相关的所有事项,这些权限已授予个别用户。

列出角色:

$ etcdctl role list

创建新角色,使用:

$ etcdctl role add myrolename

角色无密码;它仅用于定义一组新的访问权限。

角色被授予对单个键或键范围的访问权限。

范围可指定为区间 [起始键、结束键),其中起始键在字典序上应小于结束键。

访问权限可授予为读取、写入或两者兼有,例如以下示例所示:

# Give read access to a key /foo
$ etcdctl role grant-permission myrolename read /foo

# Give read access to keys with a prefix /foo/. The prefix is equal to the range [/foo/, /foo0)
$ etcdctl role grant-permission myrolename --prefix=true read /foo/

# Give write-only access to the key at /foo/bar
$ etcdctl role grant-permission myrolename write /foo/bar

# Give full access to keys in a range of [key1, key5)
$ etcdctl role grant-permission myrolename readwrite key1 key5

# Give full access to keys with a prefix /pub/
$ etcdctl role grant-permission myrolename --prefix=true readwrite /pub/

要查看已授予的权限,可随时查看角色:

$ etcdctl role get myrolename

权限撤销以相同逻辑方式进行:

$ etcdctl role revoke-permission myrolename /foo/bar

如移除角色本身:

$ etcdctl role delete myrolename

启用身份认证

启用身份认证的最小步骤如下。系统管理员可根据偏好,在启用身份认证之前或之后设置用户和角色。

确保已创建 root 用户:

$ etcdctl user add root
Password of root:

启用身份认证:

$ etcdctl auth enable

此后,etcd 已启用身份认证运行。如需出于任何原因禁用身份认证,请使用对应的反向命令:

$ etcdctl --user root:rootpw auth disable

身份认证的安全范围

当启用身份认证 etcdctl auth enable 时,可保护 V3 gRPC API 操作(get、put、delete、watch 等)。

/metrics 和 /health HTTP 端点使用独立的处理器,不受 V3 RBAC 身份认证保护。此设计允许 Prometheus 和负载均衡器在无需 gRPC 身份认证的情况下抓取指标,同时仍可保护键值数据。

为保障可观测性端点的安全:

  • 使用 --cert-file、--key-file 和 --client-cert-auth 启用 mTLS
  • 或通过 --listen-metrics-urls 将指标绑定到私有接口
  • 或使用网络策略/防火墙规则限制访问

使用 etcdctl 进行身份认证

etcdctl 支持与 curl 类似的身份认证标志。

$ etcdctl --user user:password get foo

密码可从提示中获取:

$ etcdctl --user user get foo

密码也可以从命令行标志 --password 获取:

$ etcdctl --user user --password password get foo

否则,所有 etcdctl 命令保持不变。用户和角色仍可创建和修改,但需由具备根角色的用户进行身份认证。

使用 TLS 共用名称

从 v3.2 版本起,若 etcd 服务器以选项 --client-cert-auth=true 启动,则客户端 TLS 证书中的通用名称(CN)字段将用作 etcd 用户。在此情况下,通用名称用于身份认证,客户端无需提供密码。请注意,若同时满足以下两个条件:1. --client-cert-auth=true 被传递且客户端提供了通用名称,以及 2. 客户端提供了用户名和密码,则基于用户名和密码的身份认证将被优先使用。请注意,此功能无法与 gRPC-proxy 或 gRPC-gateway 一同使用。这是因为 gRPC-proxy 会终止来自其客户端的 TLS 连接,导致所有客户端共享代理的证书。gRPC-gateway 内部使用 TLS 连接将 HTTP 请求转换为 gRPC 请求,因此存在相同的限制。因此,客户端无法正确向服务器提供其通用名称。若给定证书的通用名称非空,gRPC-proxy 将报错并停止运行。gRPC-proxy 返回错误,提示客户端证书中包含非空的通用名称。

密码强度说明

etcdctl 和 etcd API 在用户创建或更新用户密码操作期间不强制要求特定密码长度。系统管理能力应负责实施此类要求。为避免与密码强度相关的安全风险,可使用 TLS Common Name 基于的身份认证 ,或通过 --no-password 选项创建的用户。