认证

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时是双向认证, 流程如下

  1. kube-scheduler发送请求到kube-apiserver

  2. kube-apiserver将tls-cert-file配置的公钥发送给kube-scheduler

  3. kube-scheduler使用kubeconfig中的certificate-authority-data验证证书是否合法

  4. 如果证书合法kube-scheduler发送kubeconfig中的client-certificate-data给kube-apiserver

  5. kube-apiserver使用client-ca-file验证证书是否合法

  6. 如果证书全部合法可以进行通信

    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-<token id>"
  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- (Token ID 就是上一步创建的 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

最后更新于