kubernets集群中使用了多种的认证方式, 涉及到的关键词有:api-server,认证,授权,准入控制,RBAC,Service Account,客户端证书认证,Kubernetes 用户,Token 认证等等。
因为集群中所有的组件全部使用HTTP RESTFUL与kube-apiserver进行通信, 所有的client与kube-apiserver通信的过程中都会经过:
- 认证: 检查用户是否合法
- 授权: 检查请求的行为是否具有权限
- 准入机制: 检查请求的内容是否符合k8s的规范或要求
+ - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -+
' Client ' ' kube-apiserver '
' ' ' '
' +-----------------+ ' ' +----------------+ +---------------+ +-------------------+ ' +------+
' | User | ' --> ' | Authentication | --> | Authorization | --> | Admission Control | ' --> | etcd |
' +-----------------+ ' ' +----------------+ +---------------+ +-------------------+ ' +------+
' ' ' '
' ' + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -+
' +-----------------+ '
' | service-account | '
' +-----------------+ '
' '
+ - - - - - - - - - - +
Authentication
认证阶段的工作是识别用户身份,支持的认证方式有很多,比如:HTTP Base,HTTP token,TLS,Service Account,OpenID Connect 等,API Server 启动时可以同时指定多种认证方式,会逐个使用这些方法对客户请求认证,只要通过任意一种认证方式,API Server 就会认为 Authentication 成功。
kubernetes中的用户有两种:
- service-account
- 普通用户
要特别说的是普通用户在k8s中没有具体的api管理用户都是通过外部方式进行管理
认证方式:
- X509 Client Certs: 客户端证书模式需要在 kubectl 命令中加入 --client-ca-file=
参数,指明证书所在位置。这是k8s默认的方式
- bearer tokens: 在 HTTP 请求头中加入 Authorization: Bearer
。 主要适用JWT的认证方式
- Bootstrap Tokens: 与 bearer tokens 一致,但 TOKEN 格式为 [a-z0-9]{6}.[a-z0-9]{16}。该方式称为 dynamically-managed Bearer token,以 secret 的方式保存在 kube-system namespace 中,可以被动态的创建和管理。同时,启用这种方式还需要在 APIServer 中打开 --enable-bootstrap-token-auth。
- Basic Token认证方式, 通过--token-auth-file= 参数指明 bearer tokens 所在位置。
- Service Account Tokens: 该方式通常被 pod 所使用,在 PodSpec 中指明 ServiceAccount 来访问 ApiServer。
- OpenID Connect Tokens
- Webhook Token Authentication
- Basic auth: 以参数 --basic-auth-file=
指明 basic auth file 的位置。这个 basic auth file 以 csv 文件的形式存在,里面至少包含三个信息:password、username、user id,同时该模式在使用时需要在请求头中加入 Authorization: Basic BASE64ENCODED(USER:PASSWORD) 。
01.X509证书认证
建立完整TLS加密通信,需要有一个CA认证机构,会向客户端下发根证书、服务端证书以及签名私钥给客户端。ca.pem & ca-key.pem & ca.csr组成了一个自签名的CA机构。
我们把这种方式也称之为双向认证, 在所有的认证中也是最严格的认证。 需要kube-apiserver启动时指定:
- client-ca-file: 指定CA根证书文件为/etc/kubernetes/pki/ca.pem,内置CA公钥用于验证某证书是否是CA签发的证书
- tls-private-key-file: 指定ApiServer私钥文件为/etc/kubernetes/pki/apiserver-key.pem
- tls-cert-file:指定ApiServer证书文件为/etc/kubernetes/pki/apiserver.pem
0101.kubeconfig文件详解
其中client-ca-file
中指定的CA根证书会在类似kube-controller-manager
的组件通信时验证证书是否为该CA根证书签发, 目前组件访问kube-apiserver主要是通过kubeconfig的方式, kubeconfig的文件中包含根CA、根CA签发的证书的公钥和私钥, 我们以kube-scheduler的kubeconfig为例进行说明, 下面为kube-scheduler.kubeconfig
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: CA证书的base64格式
server: https://apiserver-p001.svc.gxd88.cn:6443
name: kubernetes
contexts:
- context:
cluster: kubernetes
user: system:kube-scheduler
name: default
current-context: default
kind: Config
preferences: {}
users:
- name: system:kube-scheduler
user:
client-certificate-data: CA证书签发的证书公钥
client-key-data: CA证书签发证书私钥
可以看出文件分为三大部分:clusters、contexts、users
clusters 部分
定义集群信息,包括 api-server 地址、certificate-authority-data, 其中certificate-authority-data用于服务端证书认证的自签名 CA 根证书contexts 部分
集群信息和用户的绑定,kubectl 通过上下文提供的信息连接集群。-
users 部分
多种用户类型,默认是客户端证书(x.509 标准的证书)和证书私钥,也可以是 ServiceAccount Token。这里重点说下前者:- client-certificate-data: base64 加密后的客户端证书;
- client-key-data: base64 加密后的证书私钥;
一个请求在通过 api-server 的认证后,api-server 会从收到客户端证书中取用户信息,然后用于后面的授权,这里所说的用户并不是服务账号,而是客户端证书里面的 Subject 信息:O 代表用户组,CN 代表用户名。
每个组件对应的CN和O
组件 | Common Name | Organization |
---|---|---|
Kube-apiserver | kubernetes | |
kube-scheduler | System:kube-scheduler | |
Kube-controller-manager | system:kube-controller-manager | |
Kubelet | System:node:${node_name} | system:nodes |
Kube-proxy | system:kube-proxy | |
kubectl | admin |
0102.双向认证的流程
当组件kube-scheduler
访问kube-apiserver时是双向认证, 流程如下
- kube-scheduler发送请求到kube-apiserver
- kube-apiserver将tls-cert-file配置的公钥发送给kube-scheduler
- kube-scheduler使用kubeconfig中的certificate-authority-data验证证书是否合法
- 如果证书合法kube-scheduler发送kubeconfig中的client-certificate-data给kube-apiserver
- kube-apiserver使用client-ca-file验证证书是否合法
- 如果证书全部合法可以进行通信
3.使用certificate-authority-data验证证书 5.client-ca-file验证证书
+------------------------------------+ +----------------------+
v | v |
+----------------------------------------+ 1.HTTPS Request +--------------------------+
| | -------------------------> | |
| | | |
| | 2.tls-cert-file | |
| | <------------------- | |
| kube-scheduler | | kube-apiserver |
| | 4.client-certificate-data | |
| | -------------------> | |
| | | |
| | 6.通信 | |
| | <------------------- | |
+----------------------------------------+ +--------------------------+
02.Static Token File
kube-apiserver启动时需要使用--token-auth-file=bootstrap-token.csv
客户端请求的时候需要在http header中加入:”Authorization: Bearer THETOKEN”,如下实例:
curl -k --header "Authorization: Bearer e5fc5f662ea596befbe5ababc731a5c3" https://127.0.0.1:6443/api
{
"kind": "APIVersions",
"versions": [
"v1"
],
"serverAddressByClientCIDRs": [
{
"clientCIDR": "0.0.0.0/0",
"serverAddress": "10.40.61.116:6443"
}
]
}
或者使用kubectl:
kubectl --server=https://127.0.0.1:6443 \
--token=e5fc5f662ea596befbe5ababc731a5c3 \
--insecure-skip-tls-verify=true \
cluster-info
03.Bootstrap Tokens认证
Bootstrap Token 和 Static Token的区别是Bootstrap Token在 k8s 中动态的管理一种type为bootstrap token的token,这些token作为secret放在kube-system namespace中。controller-manager中的tokencleaner controller会在bootstrap token 过期时进行删除。
生成Bootstrap Token:
$ echo "$(head -c 6 /dev/urandom | md5sum | head -c 6)"."$(head -c 16 /dev/urandom | md5sum | head -c 16)"
f455f5.db29ddb7b7d01ab9
这个 f455f5.db29ddb7b7d01ab9 就是生成的 Bootstrap Token,保存好 token,因为后续要用;关于这个 token 解释如下:
Token 必须满足 [a-z0-9]{6}.[a-z0-9]{16} 格式;以 . 分割,前面的部分被称作 Token ID,Token ID 并不是 “机密信息”,它可以暴露出去;相对的后面的部分称为 Token Secret,它应该是保密的
创建 Bootstrap Token Secret:
对于 Kubernetes 来说 Bootstrap Token Secret 也仅仅是一个特殊的 Secret 而已;对于这个特殊的 Secret 样例 yaml 配置如下:
apiVersion: v1
kind: Secret
metadata:
# Name MUST be of form "bootstrap-token-"
name: bootstrap-token-07401b
namespace: kube-system
# Type MUST be 'bootstrap.kubernetes.io/token'
type: bootstrap.kubernetes.io/token
stringData:
# Human readable description. Optional.
description: "The default bootstrap token generated by 'kubeadm init'."
# Token ID and secret. Required.
token-id: f455f5
token-secret: db29ddb7b7d01ab9
# Expiration. Optional.
expiration: 2200-01-01T00:00:11Z
# Allowed usages.
usage-bootstrap-authentication: "true"
usage-bootstrap-signing: "true"
# Extra groups to authenticate the token as. Must start with "system:bootstrappers:"
auth-extra-groups: system:bootstrappers:worker,system:bootstrappers:ingress
需要注意几点:
作为 Bootstrap Token Secret 的 type 必须为 bootstrap.kubernetes.io/token,name 必须为 bootstrap-token-
usage-bootstrap-authentication、usage-bootstrap-signing 必须存才且设置为 true
expiration 字段是可选的,如果设置则 Secret 到期后将由 Controller Manager 中的 tokencleaner 自动清理
auth-extra-groups 也是可选的,令牌的扩展认证组,组必须以 system:bootstrappers: 开头
最后使用kubectl create -f bootstrap.secret.yaml
创建即可
04.Service Account Tokens
Service Account Token 是一种比较特殊的认证机制,适用于上文中提到的pod内部服务需要访问apiserver的认证情况,默认enabled。
apiserver 的启动配置参数有--service-account-key-file=/srv/kubernetes/pki/service-account.pem
,用于检验 ServiceAccount 的 token, 如果没有指明文件,默认使用–tls-private-key-file
的值,即API Server的私钥。
controller-manager的启动配置参数--service-account-private-key-file=/srv/kubernetes/pki/service-account-key.pem
该文件是PEM 编码的 X509 RSA,用于签署 Service Account Token。
特别说明:
apiserver 和 controller-manager中指定的key可以是同一个文件, 可以直接使用如下命令生成
openssl genrsa -out private.key 4096
0401.资源说明
service accout本身是作为一种资源在k8s集群中,我们可以通过命令行获取
$ kubectl get serviceaccount --all-namespaces | grep default
default default 1 8d
kube-node-lease default 1 8d
kube-public default 1 8d
kube-system default 1 8d
默认的情况下k8s会在集群中的所有namespace创建一个default的serviceaccount,并且这个serviceaccount关联一个default-token-xxxx这样的token
查看serviceaccout和token的对应关系:
kubectl get serviceaccount default -n kube-system -o yaml
apiVersion: v1
imagePullSecrets:
- name: wcr-secret
kind: ServiceAccount
metadata:
creationTimestamp: "2018-06-19T09:03:28Z"
name: default
namespace: kube-system
resourceVersion: "116579"
selfLink: /api/v1/namespaces/kube-system/serviceaccounts/default
uid: a1eec26f-739f-11e8-bd8f-00163e0ed17a
secrets:
- name: default
- name: default-token-xl2hw
查看default-token的具体内容:
kubectl get secret default-token-xl2hw -n kube-system -o yaml
apiVersion: v1
data:
ca.crt: xxxx
namespace: xxxx
token:xxxx
kind: Secret
metadata:
creationTimestamp: "2018-06-19T09:03:28Z"
name: default-token-xl2hw
namespace: kube-system
resourceVersion: "234"
selfLink: /api/v1/namespaces/kube-system/secrets/default-token-xl2hw
uid: a1f3334f-739f-11e8-bd8f-00163e0ed17a
type: kubernetes.io/service-account-token
可以看到default-token-xl2hw资源包含的数据有三部分:
ca.crt,这是API Server的CA公钥证书,用于Pod中的Process对API Server的服务端数字证书进行校验时使用的;
namespace,这是Secret所在namespace的值的base64编码:# echo -n “kube-system”|base64 => “a3ViZS1zeXN0ZW0=”
token:该token就是由service-account-key-file的值签署(sign)生成。
这种认证方式主要由k8s集群自己管理,用户用到的情况比较少。我们创建一个pod时,默认就会将该namespace对应的默认service account token mount到Pod中,所以无需我们操作便可以直接与apiserver通信
05.OpenID Connect Tokens
如果集群需要根据用所属的部门或者职能进行权限划分最好使用OpenID的方式进行访问授权。
06.参考
官方文档Authenticating
Kubernetes-- 漫谈kubernetes 中的认证 & 授权 & 准入机制
Kubernetes 的证书认证
Kubernetes TLS bootstrapping 那点事
使用 Bootstrap Token 完成 TLS Bootstrapping