Kubernetes 19 梳理出UserAccount用户账号一条线

前言

用户账号一条线就是从集群外访问进来的,服务账号一条线就是集群内之间访问,相同点都是都通过 apiserver,都需要认证、授权、准入控制。

客户端访问 API 服务的途径通常有三种:kubectl、客户端库(如 fabric8)或者直接使用 REST 接口进行请求。无论哪种方式,归根结底都是从集群外访问进入 k8s 集群。从集群外访问 k8s 集群,走的就是 UserAccount 认证体系,一共有四种认证方式:X509 客户端证书,静态 token 文件,静态账号密码文件,请求头中添加 bearer。

无论哪种方式,对于所有通过身份认证的用户,system:authenticated 组都会被添加到其组列表中。

Kubernetes 19 梳理出UserAccount用户账号一条线

你可以同时启用多种身份认证方法,并且你通常会至少使用两种方法:

(1) 针对服务账号 ServiceAccount 使用服务账号令牌
(2) 至少另外一种方法对用户的身份进行认证

kubectl api-resources --verbs=list --namespaced -o name

解释

-o 表示输出 -o name 表示仅仅输出名称 (类似 mysql 语句中 select 的功能)

Kubernetes 19 梳理出UserAccount用户账号一条线

一、六种认证方式

Kubernetes 有以下六种鉴权方法:

(1) 客户端证书
(2) 不记名令牌:Static Token File(静态令牌)、Service Account Tokens(服务账号令牌)、OpenID Connect Tokens(OIDC 令牌)
(3) 启动引导令牌
(4) Webhook Token Authentication
(5) Authenticating Proxy 第三方授权协议
(6) 匿名请求(不需要身份认证,直接给 system:anonymous 未授权用户组绑定上 cluster-admin 这个最高权限的 cluster-role)

当 HTTP 请求发送到 API Server 时,Kubernetes 会从 Request 中关联以下信息:

Username:用户名,用来辨识最终用户的字符串,比如 kube-admin
UID:用户 ID,代表用户的唯一 ID
Groups:用户组,代表逻辑相关的一组用户,
Extra Fields,扩展字段,鉴权可能需要的其他信息

需要注意的是,当多种鉴权方法同时启用时,第一个鉴权方法鉴权成功即通过验证,其它方法不再鉴权,同时 api-server 也不保证鉴权方法的顺序。所有鉴权成功的用户都会加到 group “system:authenticated”中。

二、X509 客户证书(最重要的用户账号凭证文件,默认方式)

通过给 API 服务器传递 --client-ca-file=SOMEFILE 选项,就可以启动客户端证书身份认证。所引用的文件必须包含一个或者多个证书机构,用来验证向 API 服务器提供的客户端证书。如果提供了客户端证书并且证书被验证通过,则 subject 中的公共名称(Common Name)就被 作为请求的用户名。自 Kubernetes 1.4 开始,客户端证书还可以通过证书的 organization 字段标明用户的组成员信息。要包含用户的多个组成员信息,可以在证书种包含多个 organization 字段。

开发中最常用的,无论是 /etc/kubernetes/pki/ca.crt 文件认证,还是 /root/.kube/config 文件(从 /etc/kubernetes/admin.conf 文件复制过来) ,本质都是 x509 ca 客户端证书认证,两种文件原理是一样的。

所以说,x509 ca 客户端证书认证是最重要的认证方式。

Kubernetes 19 梳理出UserAccount用户账号一条线

三、在 HTTP 请求中放入持有者令牌/不记名令牌(bearer)

持有者令牌/不记名令牌,英文是 bearer ,就是持有者的意思,如下:

Kubernetes 19 梳理出UserAccount用户账号一条线

在 Kubernetes 中,主要有以下几种使用不记名令牌(Bearer token)的方法:

Static Token File(静态令牌)
Service Account Tokens(服务账号令牌)
OpenID Connect Tokens(OIDC 令牌)

Static Token File(静态令牌)

当 API 服务器的命令行设置了 --token-auth-file=SOMEFILE 选项时,会从文件中 读取持有者令牌。目前,令牌会长期有效,并且在不重启 API 服务器的情况下 无法更改令牌列表。

令牌文件是一个 CSV 文件,包含至少 3 个列:令牌、用户名和用户的 UID。其余列被视为可选的组名。

如果要设置的组名不止一个,则对应的列必须用双引号括起来,例如

token,user,uid,"group1,group2,group3"

Service Account Tokens(服务账号令牌)

1.创建一个 k8s-admin.yaml

apiVersion: v1
kind: ServiceAccount
metadata:
name: dashboard-admin
namespace: kube-system
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: dashboard-admin
subjects:
- kind: ServiceAccount
name: dashboard-admin
namespace: kube-system
roleRef:
kind: ClusterRole
name: cluster-admin
apiGroup: rbac.authorization.k8s.io

在 RBAC 权限中,能够与 role/clusterrole 绑定的只有三种资源,分别是:kind: User、kind: Group、kind: ServiceAccount ,所以,这里 ServiceAccount 绑定 ClusterRole,很正常
注意:从来没有一种 kind: UserAcccount 的资源

2.应用 k8s-admin.yaml 配置

kubectl apply -f k8s-admin.yaml

3.获取 admin-token 名字

kubectl get secret -n kube-system|grep admin

4.Describe 查询 token 内容

kubectl describe secret dashboard-admin-token-slc8x -n kube-system

Kubernetes 19 梳理出UserAccount用户账号一条线

Kubernetes 19 梳理出UserAccount用户账号一条线

Kubernetes 19 梳理出UserAccount用户账号一条线

请求头上增加 ​​bearer 具体token​

Kubernetes 19 梳理出UserAccount用户账号一条线

OpenID Connect Tokens(OIDC 令牌)

OpenID Connect 是一种 OAuth2 认证方式,Kubernetes 可以利用 OAuth2 Token Response 中的 ID Token 作为 Bearer Token 进行认证访问。

其流程如下:

Kubernetes 19 梳理出UserAccount用户账号一条线

(1) 登录到你的身份服务(Identity Provider)
(2) 你的身份服务将为你提供 access_token、id_token 和 refresh_token
(3) 在使用 kubectl 时,将 id_token 设置为 --token 标志值,或者将其直接添加到 kubeconfig 中
(4) kubectl 将你的 id_token 放到一个称作 Authorization 的头部,发送给 API 服务器
(5) API 服务器将负责通过检查配置中引用的证书来确认 JWT 的签名是合法的
(6) 检查确认 id_token 尚未过期
(7) 确认用户有权限执行操作
(8) 鉴权成功之后,API 服务器向 kubectl 返回响应
(9) kubectl 向用户提供反馈信息

四、启动引导令牌

为了支持方便地启动引导新的集群,Kubernetes 包含了一种动态管理的 bearer token 类型,称作启动引导令牌(Bootstrap Token)。这些令牌以 Secret 的形式保存在 kube-system namespace 中,可以被动态管理和创建。控制器管理(Controller Manager)器包含的 TokenCleaner 控制器能够在启动引导令牌过期时将其删除。

Bootstrap Token 令牌的格式为 [a-z0-9]{6}.[a-z0-9]{16}。第一个部分是令牌的 ID;第二个部分是令牌的 Secret。可以用如下所示的方式在 HTTP 头部设置令牌:

#781292就是用户ID
Authorization: Bearer 781292.db7bc3a58fc5f07e

在 API Server 上设置 –enable-bootstrap-token-auth 标志来启用基于启动引导令牌的身份认证组件。

必须通过控制器管理器的 –controllers 标志来启用 TokenCleaner 控制器:--cnotallow=*,tokencleaner

如果使用 kubeadm 来启动引导新的集群时自动完成这些设置。

身份认证组件的认证结果为 system:bootstrap:<令牌 ID>,该用户属于 system:bootstrappers 用户组。

这里的用户名和组设置都是有意设计成这样,其目的是阻止用户在启动引导集群之后继续使用这些令牌。这里的用户名和组名可以用来在启动引导新的的集群时构造合适的鉴权策略(kubadm 中使用)。

五、Webhook Token Authentication

Webhook 身份认证是一种用来验证 bearer token 的回调机制。

–authentication-token-webhook-config-file:指向一个配置文件,其中描述如何访问远程的 Webhook 服务。

–authentication-token-webhook-cache-ttl:用来设定身份认证的缓存时间。默认时长为 2 分钟。

–authentication-token-webhook-version:指定 TokenReview 对象的使用版本,authentication.k8s.io/v1beta1 或者 authentication.k8s.io/v1,默认为 v1beta1。TokenReview 对象用于从 webhook 中发送或接收信息。

配置文件使用 kubeconfig 文件的格式。文件中,clusters 指代远程服务,users 指代远程 API 服务 Webhook。

# Kubernetes API 版本
apiVersion: v1
# API 对象类别
kind: Config
# clusters 指代远程服务
clusters:
- name: name-of-remote-authn-service
cluster:
certificate-authority: /path/to/ca.pem # 用来验证远程服务的 CA
server: https://authn.example.com/authenticate # 要查询的远程服务 URL。必须使用 'https'。
# users 指代 API Server的 Webhook 配置
users:
- name: name-of-api-server
user:
client-certificate: /path/to/cert.pem # Webhook 插件要使用的证书
client-key: /path/to/key.pem # 与证书匹配的密钥
# kubeconfig 文件需要一个上下文(Context),此上下文用于本 API Servercurrent-context: webhook
contexts:
- context:
cluster: name-of-remote-authn-service
user: name-of-api-sever
name: webhook

当客户端尝试在 API Server 上使用 bearer token 完成身份认证时, 身份认证 Webhook 会用 POST 请求发送一个 JSON 序列化的对象到远程服务。该对象是 authentication.k8s.io/v1beta1 组的 TokenReview 对象, 其中包含 bearer token。

POST 请求 Body:

{  "apiVersion": "authentication.k8s.io/v1beta1",  "kind": "TokenReview",  "spec": {    "token": "<持有者令牌>"  }}

远程服务会填充请求的 status 字段,以标明登录操作是否成功,并还返回用户信息。

{
"apiVersion": "authentication.k8s.io/v1beta1",
"kind": "TokenReview",
"status": {
"authenticated": true, // 认证失败返回false
"user": {
"username": "janedoe@example.com",
"uid": "42",
"groups": [
"developers",
"qa"
],
"extra": {
"extrafield1": [
"extravalue1",
"extravalue2"
]
}
}
}
}

六、Authenticating Proxy 第三方授权协议

API Server 可以配置成从请求头的字段值(如 X-Remote-User)中识别用户。主要是用来与身份认证代理一起使用,代理负责设置请求头的字段值。配置参数:

  1. –requestheader-username-headers:必需字段,大小写不敏感。用来设置要获取用户身份的请求头字段名,可以指定多个,在请求中第一个有数值的字段会被用来提取用户名。
  2. –requestheader-group-headers:可选字段,在 Kubernetes 1.6 版本以后支持,大小写不敏感。建议设置为 “X-Remote-Group”。用来根据配置的请求头名称获取用户所属的组名。所找到的全部头部字段的取值都会被用作用户组名。
  3. –requestheader-extra-headers-prefix 可选字段,在 Kubernetes 1.6 版本以后支持,大小写不敏感。建议设置为 “X-Remote-Extra-”。用来设置一个头部字段的前缀字符串,API Server 会基于所给前缀来查找与用户有关的一些额外信息。这些额外信息通常用于所配置的鉴权插件。API Server 会将与所给前缀匹配的头部字段过滤出来,去掉其前缀部分,将剩余部分转换为小写字符串并在必要时执行 percent-decoded 解码后,作为新的附加信息字段扩展键名。header 的值作为扩展键的值。

Api Server 配置示例:

--requestheader-username-headers=X-Remote-User
--requestheader-group-headers=X-Remote-Group
--requestheader-extra-headers-prefix=X-Remote-Extra-

请求头:

GET / HTTP/1.1X-Remote-User: fidoX-Remote-Group: dogsX-Remote-Group: dachshundsX-Remote-Extra-Acme.com%2Fproject: some-projectX-Remote-Extra-Scopes: openidX-Remote-Extra-Scopes: profile

认证后的用户信息为:

name: fidogroups:- dogs- dachshundsextra:  acme.com/project:  - some-project  scopes:  - openid  - profile

X-Remote-Extra-Acme.com%2Fproject 去掉了*X-Remote-Extra-*前缀,Acme.com%2Fproject 经过 percent-decoded 解码后作为扩展字段的 key,请求头的值作为该扩展字段键的值。

为了防止请求头欺骗,在检查请头之前,需要身份验证代理向 API Server 提供有效的客户端证书,以便针对指定的 CA 进行验证。相关配置:

–requestheader-client-ca-file:必需字段,PEM 编码的证书包。在检查请求头中的用户名之前,必须提供有效的客户端证书并根据指定文件中的证书颁发机构进行验证。
–requestheader-allowed-names:可选字段,用来给出一组公共名称(CN)。如果设置了,则必须在检查请求头的用户名之前提供具有指定列表中的 CN 的有效客户端证书。如果为空,则允许任何 CN。

七、匿名请求

启用匿名请求支持之后,如果请求没有被已配置的其他身份认证策略拒绝,则被视作匿名请求(Anonymous Requests)。这类请求的用户名为:system:anonymous,对应的用户组为:system:unauthenticated。

在一个配置了令牌身份认证且启用了匿名访问的服务器上,如果请求提供了非法的 bearer token,则会返回 401 Unauthorized 错误。如果请求没有提供 bearer toekn,则被视为匿名请求。

启用匿名请求语句:

kubectl create clusterrolebinding test:anonymous --clusterrole=cluster-admin --user=system:anonymous

将 system:anonymous 用户组中的用户,绑定到最高权限的 cluster-admin 上面去,这样匿名权限就可以直接操作 k8s 集群,如下:

Kubernetes 19 梳理出UserAccount用户账号一条线


总结

Human 人使用的是 User 和 UserGroup,使用的 x509 客户证书、静态 token、账号密码

对于 UserAccount 所有的认证方式,都是要通过 apiserver 的,如果是 kubeadm init 安装的 k8s 集群,查看
如果有 --client-ca-file=SOMEFILE ,则启用 x509 ca 客户端证书认证;
如果有 --token-auth-file=SOMEFILE,则启用 静态令牌证书认证;
如果有–enable-bootstrap-token-auth,则启用基于引导令牌的身份认证。

默认情况下,采用的是 x509 ca 客户端证书认证,并且启用基于引导令牌的身份认证

Pod 使用的是 ServiceAccount,里面的 namespace+ca.crt+token 保留在 secrets 中,本质是基于 ca 证书认证的方式。

三项资源 User、UserGroup 和 ServiceAccount,都是可以根据 RBAC 规则与 Role/ClusterRole 绑定的。

- END -


发表评论

相关文章