赞
踩
用户账号一条线就是从集群外访问进来的,服务账号一条线就是集群内之间访问,相同点都是都通过apiserver,都需要认证、授权、准入控制。
Pod只有一种方式连接K8S集群,那就是sa账号,可以是默认新建的,也可以是手动新建的。用户就有多种方式访问API服务,通常有三种:kubectl、客户端库(如fabric8)或者直接使用 REST接口进行请求。无论哪种方式,归根结底都是从集群外访问进入k8s集群。从集群外访问k8s集群,走的就是UserAccount认证体系,底层都是 user/userGroup 绑定某个具体的 role,一共有四种认证方式:X509客户端证书,静态token文件,静态账号密码文件,请求头中添加bearer。
无论哪种方式,对于所有通过身份认证的用户,system:authenticated 组都会被添加到其组列表中。
你可以同时启用多种身份认证方法,并且你通常会至少使用两种方法:
(1) 针对服务账号ServiceAccount使用服务账号令牌
(2) 至少另外一种方法对用户的身份进行认证
kubectl api-resources --verbs=list --namespaced -o name
解释
-o 表示输出 -o name 表示仅仅输出名称 (类似mysql语句中select的功能)
Kubernets API Server进程提供Kuvernetes API。通常情况下,有一个进程运行在单一kubernetes-master节点上。
默认情况,Kubernetes API Server提供HTTP的两个端口:
本地主机端口/InSecure Port
HTTP服务
默认端口8080,修改标识–insecure-port
默认IP是本地主机,修改标识—insecure-bind-address
在HTTP中没有认证和授权检查
主机访问受保护
Secure Port
默认端口6443,修改标识—secure-port
默认IP是首个非本地主机的网络接口,修改标识—bind-address
HTTPS服务。设置证书和秘钥的标识,–tls-cert-file,–tls-private-key-file
认证方式,令牌文件或者客户端证书
使用基于策略的授权方式
本来想实验一下,但是 k8s v1.21.0 这里不能试验这个 insecure-port 参数了
而且 k8s 官网也没有对于 apiserver 两个参数 insecure-port 和 insecure-bind-address 的介绍,只有 secure-port 和 bind-address 这两个参数,见 k8s官网apiserver参数列表介绍
Kubernetes 有以下六种鉴权方法(请求只要满足其中任意一种既可以成功访问到APIServer):
(1) X509客户端证书
(2) 不记名令牌Token: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”中。
通过给 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客户端证书认证是最重要的认证方式。
小结:ca.crt 底层还是 用户/组织 ,这个用户一定绑定了 role,才有权限通过 apiserver 的授权认证,操作 k8s 集群。
持有者令牌/不记名令牌,英文是 bearer ,就是持有者的意思,如下:
在 Kubernetes 中,主要有以下几种使用不记名令牌(Bearer token)的方法:
Static Token File(静态令牌)
Service Account Tokens(服务账号令牌)
OpenID Connect Tokens(OIDC 令牌)
当 API 服务器的命令行设置了 --token-auth-file=SOMEFILE 选项时,就是 /etc/kubernetes/manifests/kube-apiserver.yaml 文件中设置了 --token-auth-file=SOMEFILE 选项时,会从文件中 读取持有者令牌。目前,令牌会长期有效,并且在不重启 API 服务器的情况下 无法更改令牌列表。
令牌文件是一个 CSV 文件,包含至少 3 个列:令牌、用户名和用户的 UID。 其余列被视为可选的组名。
如果要设置的组名不止一个,则对应的列必须用双引号括起来,例如
token,user,uid,"group1,group2,group3"
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
请求头上增加 bearer 具体token
小结:底层原理还是 serviceAccount 绑定 role/clusterRole 的 rbac 授权认证,这里就是 serviceAccount: dashboard-admin
绑定 clusterRole: cluster-admin。
OpenID Connect 是一种 OAuth2 认证方式,Kubernetes 可以利用 OAuth2 Token Response 中的 ID Token 作为 Bearer Token 进行认证访问。
其流程如下:
(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 控制器: --controllers=*,tokencleaner
如果使用 kubeadm 来启动引导新的集群时自动完成这些设置。
身份认证组件的认证结果为 system:bootstrap:<令牌 ID>,该用户属于 system:bootstrappers 用户组。
这里的用户名和组设置都是有意设计成这样,其目的是阻止用户在启动引导集群之后继续使用这些令牌。 这里的用户名和组名可以用来在启动引导新的的集群时构造合适的鉴权策略(kubadm中使用)。
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"
]
}
}
}
}
API Server可以配置成从请求头的字段值(如 X-Remote-User)中识别用户。 主要是用来与身份认证代理一起使用,代理负责设置请求头的字段值。配置参数:
–requestheader-username-headers
设定:必需字段,大小写不敏感。
作用:用来设置要获取用户身份的请求头字段名,可以指定多个,在请求中第一个有数值的字段会被用来提取用户名。
–requestheader-group-headers
设定:可选字段,在 Kubernetes 1.6 版本以后支持,大小写不敏感。 建议设置为 “X-Remote-Group”。
作用:用来根据配置的请求头名称获取用户所属的组名。所找到的全部头部字段的取值都会被用作用户组名。
–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.1 X-Remote-User: fido \
X-Remote-Group: dogs \
X-Remote-Group: dachshunds \
X-Remote-Extra-Acme.com%2Fproject: some-project \
X-Remote-Extra-Scopes: openid \
X-Remote-Extra-Scopes: profile
认证后的用户信息为:
name: fido
groups:- dogs- dachshunds
extra: 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
停用匿名请求:
kubectl delete clusterrolebinding test:anonymous
底层原理:还是 user/userGroup 绑定 role/clusterRole,然后就可以有权限通过 apiserver 授权认证。这里就是将 system:anonymous 用户组中的用户,绑定到最高权限的 cluster-admin 上面去,这样匿名权限就可以直接操作 k8s 集群,如下:
开启 TLS时,所有的请求都需要首先认证。Kubernetes支持多种认证机制,并支持同时开启多个认证插件(只要有一个认证通过即可)。
如果认证成功,则用户的 username 会传入授权模块做进一步授权验证;而对于认证失败的请求则返回 HTTP 401。
当apiserver启动的时候,其实有两个和安全相关的配置,一个叫insecure-port,一个叫secure-port,早期大家很习惯的将insecure-port打开,经过insecure-port端口所有的请求其实是没有做任何的安全校验的,也就是认证,鉴权这些逻辑是不走的,这样就面临着一个危险,所有的request是没有认证的,不管是谁发的,它有没有权限,它都会被接受,这很可能就会有一些恶意的请求。
所以现在在非生产环境也会将insecure端口关掉。
另外一个是secure port,secure-port设置之后所有的认证,鉴权这些逻辑都要走。
cat kube-apiserver.yaml
--secure-port=6443 \
secure-port:6443是需要认证授权的,insecure-port是不需要认证授权的,apiserver对于secure-port有不同的认证方式。
(1) 通过设置 --client-ca-file=SOMEFILE ,可以打开x509客户证书认证方式;
(2) 通过设置 --token-auth-file=SOMEFILE ,可以打开静态Token 文件认证方式,该文件为 csv格式,每行至少包括三列 token,username,user id,token,user,uid,“group1,group2,group3”;
(3) 通过设置 --basic-auth-file=SOMEFILE,可以打开静态密码 文件认证方式,该文件格式为csv,每行至少三列 password,user,uid,后面是可选的group名 password,user,uid,“group1,group2,group3”。(和静态token类似,只不过文件里面存放着密码)
Human(人) 使用的是User和UserGroup,使用的x509客户证书、静态token、账号密码
对于UserAccount所有的认证方式,都是要通过apiserver的,如果是 kubeadm init 安装的k8s集群,查看 /etc/kubernetes/manifest/kube-apiserver.yaml,如下:
如果有 --client-ca-file=SOMEFILE ,则启用 x509 ca客户端证书认证;
如果有 --token-auth-file=SOMEFILE,则启用 静态令牌证书认证;
如果有–enable-bootstrap-token-auth,则启用基于引导令牌的身份认证。
默认情况下,采用的是 x509 ca客户端证书认证,并且启用基于引导令牌的身份认证
Pod 使用的是 ServiceAccount,里面的 namespace+ca.crt+token 保留在 secrets 中.
三项资源 User、UserGroup和ServiceAccount,都是可以根据 RBAC 规则与 Role/ClusterRole 绑定的。
参考资料:
自定义x509客户端证书(实践)
自定义x509客户端证书(实践)
k8s-身份认证与权限(理论)
k8s 多租户_k8s用户安全管理模型简析(理论)
Kubernetes API Server 的认证机制(理论)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。