kubernetes 集群安全认证

kubernetes 集群安全认证

对于认证来说,说白了就是当我们的一些用户或者是我们的 Pod 去访问到 API server 的时候来进行一个身份的识别,这就是我们所谓的认证。在 K8S 中认证分为以下几种:

  • HTTP Token 认证:通过一个 Token 或者理解为通过一个字符串来识别合法用户。

    • HTTP Token 的认证是用一个很长的特殊编码方式并且难以被模仿的字符串 – Token 来表达客户的一种方式。Token 是一个很长的复杂的字符串,每一个 Token 对应一个用户名存储在 API server 能够访问的文件中,也就是这种访问的存储方式并不是存储在 ETCD 中的,而是一个文件中所以它的安全性可想而知。当客户端发起 API 调用请求时,需要在 HTTP Header 放入 Token,这样的话我们的 API server 在收到请求会分析这个请求中的 header 里面是否存在这个 Token ,如果有的话并且匹配到了对应的用户的话那就会有对应的一些用户权限的通过。

    • HTTP Base 认证:通过 用户名+密码 的方式来认证

    • 用户名+:+密码 用 BASE64 算法进行编码后的字符串放在 HTTP Request 中 Headther Authorization 域里发送给服务端,服务端收到后进行编码也就是解码,获取用户名以及密码。这样的话我们的服务器就知道了这个用户的用户名和密码,确定成功以后判断我们整个环境中到底有没有这个用户以及密码,有就认证通过,没有就拒绝。

  • 最严格的是 HTTPS 证书认证:基于 CA 根证书签名的客户端身份认证方式,在我们整个 K8S 的域中会签署一个 CA 根证书,所有节点的证书都是以这个 CA 根证书进行签发出来的子证书,并且实现的是一个 https 的双向认证。

    注意:

    其中 HTTP Token 和 HTTP Base 这两种认证方式都不太安全,因为都是给了我们的服务器认证了我们客户端的机会,但是客户端根本没有认证服务器。也就一直认为这服务器可以认证客户端是否是一个合法的,但是客户端不知道这个服务器是不是真的,万一是一个假的呢?并且像 HTTP Token 这种将用户的认证信息放入到文件中肯定是不安全的,然后像 HTTP Base 这种用户名密码机制太费劲。

    那有没有更合理的并且能够双向认证的机制呢,当然有那就是 HTTPS 证书认证

基本上现在的企业中都会选择 HTTPS 证书认证,因为前两种安全性确实没有第三种高,第三中是一个非常稳定的这么一个机制。并且我们的 K8S 都是通过所谓的 http 协议进行所谓的 C/S 结构的开发,所以 https 是一个非常好的加密方案。

10.2.1 HTTPS 证书认证过程

上图中这是一个 HTTPS 的双向认证过程,首先我们的客户会向当前 K8S 服务器中的 私有CA 去申请证书以及下发证书,并且服务器端也需要申请和下发证书。也就是 API server 会有自己的证书和私钥,客户端也需要自己的证书和私钥。

然后当我们的客户端想去访问到服务器的时候,我们需要去发送证书进行认证,服务器端也会返回自己的证书给我们的客户端进行认证,说白了这就是一个双向认证。全部认证通过以后再通过我们的随机密钥进行加密,然后再进行所谓的发送数据。这个和我们之前的 https 单项加密其实就是相当于重来了一遍。

10.2.2 需要认证的节点

再上图中大家也可以看得到,不管是我们的组件比如说是 controller manager 、scheduler、ETCD 还是我们的 kubelet、kubeproxy 都需要访问到我们对应的 API server,既然需要访问的话他们之间就需要进行一个加密,以及有的 pod 也需要去访问到我们的 API server,比如我们的 coredns 也需要访问到 API server 进行数据的获取,那也就意味着也需要对 API server 做一个双向认证的证书存在,这就是我们需要认证的一些节点。

我们都知道加密的交互是一个需要消耗资源的过程,如果是有一些不必要的消耗的话对我来说就已经没有什么意义。对于我们的 controller manager 和 scheduler 是在我们 k8s master 组件的本身去和 API server 进行交互的,因为他们和 API server 处于同一台机器,所以直接使用 API server 的非安全端口访问即可,也就是访问本机回环接口即可访问到我们的 API server 。这是一个非安全的端口也就是说没有 https 加密,当然我们可以在 K8s 的 master 节点上去启用关闭我们的非安全性接口,这样的话 controller manager 和 scheduler 就必须访问我们的 https 加密的这么一个端口,当然这里需不需要设置还得靠自己来判断。因为本地访问已经就没有所谓的安全性可言了。

认证得两种类型:

  • kubernetes 组件对 API server 的访问:kubectl、Controller Manager、Scheduler、kubelet、kube-proxy

  • kubernetes 管理的 pod 对容器的访问:pod (dashborad 也是以 pod 形式运行)

安全性说明:

  • Controller Manager、Scheduler 与 API Server 在同一个台机器上,所以直接可以使用 API server 的非安全端口访问,--insecure-bind-address=127.0.0.1也就是本机的回环网卡。

  • kubectl、kubelet、kube-proxy 访问 API server 都需要进行 https 证书的双向认证

    • 因为 kubectl、kubelet、kube-proxy 这三个组件的访问方式是一个远程的访问过程,所以就必须要去通过我们的 HTTPS 的双向认证,这样的话安全性才会提升,能够防止第三方攻击。

证书颁发:

  • 手动签发:通过 K8s 集群的根 CA 进行签发 HTTPS 证书。

  • 自动签发:kubelet 首次访问 API server 时,使用 Token 做认证,通过之后,Controller Manager 会为 kubelet 生成一个证书,以后的访问都是用这个证书做认证。

  • 也就是最开始的时候我们这些组件的沟通是一个手动的过程,当我们的 kubelet 访问 API server 的时候它会自动颁发证书,这是不同组件之间的颁发证书的策略问题。当然我们的 kubernetes 安装方式是一个 kubeadm 的安装方式,所以我们根本没有涉及到手动签发的方式,都是自动完成的。

10.2.3 认证关键字

10.2.3.1 kubeconfig:

kubeconfig,是我们需要给大家解释的另一个关键字了,这是一个文件类型。kubeconfig 文件包含了集群参数(CA 证书、API server 地址),我们就可以把 kubeconfig 理解为是一个认证函,里面包含了我们怎么去访问一个服务的信息以及认证信息都会在 kubeconfig 之中。客户端参数(上面生成的证书和私钥),集群的 context 信息(集群名称、用户名)。kubernetes 组件通过启动时指定不同的 kubeconfig 文件可以切换到不同的集群。也就是 kubeconfig 文件它既是一个集群的描述,也是集群认证信息的这么一个填充,它会在我们的家目录下去创建一个隐藏目录。里面会拷贝一个文件,并且赋予对应的身份其实这个文件就是我们的 kubeconfig 文件。

# 进入到 kube 的隐藏文件中
[12:39:42 root@master-1 ~]#cd .kube/

# 通过 ls 查看就会发现有一个 config 文件
[13:27:54 root@master-1 .kube]#ls
cache  config  http-cache
[13:27:59 root@master-1 .kube]#cat config 

在这里都会有体现,这就是一个完整的 config 文件,包含了集群的访问方式以及认证信息等等

10.2.3.2 ServiceAccount(简称 SA )

SA 是我们 pod 中的容器和我们 API server 进行交互认证的这么一个关键指标,那为什么要使用 SA 呢,因为 pod 的创建、销毁是动态的,所以要为它手动生成证书就不可行。 kubernetes 使用了 Service Account 解决了 pod 访问 API server 的认证问题,当然它也是一种文件,包含了私钥、包含了命名空间等一些重要信息

动态的含义就是现在可能它创建出来几十个几百个 pod 那如果必须要采用我们的 https 证书认证的过程就需要新建出来几十个几百个证书,然后并且这个 pod 会被随时销毁,销毁完了之后就相当于这些证书就毁掉了。这个过程是非常消耗资源的,如果每次创建 pod 都需要创建证书的话这个对集群的压力是非常大的,所以给它一种可以循环认证的这么一种机制就是我们的 SA 。

10.2.3.3 Secrte 与 SA 的关系

我们之前讲 sercte 的时候就见到了其中以一种叫做 SA 。kubernetes 设计了一种资源对象叫做 secret,并且这个 secret 分为两类,一种是用于 ServiceAccount (SA)的 service-account-token 服务访问的 token,另一种是用于保存用户自定义密码的信息 opaque。service account 中用到包含三个部分:Token、ca.crt、namespace。

  • Token 是使用 API server 私钥签名的 JWT 。用于访问 API server 时,server 端认证。

    • 也就意味对于我们这种服务的访问是使用 token 进行所谓的传递私钥信息密钥信息,并且我们的 CA 证书是一个私有的,是我们整个 K8S 集群中私有的,所以对于认证方来说需要提供一个基本的 K8S 中的 CA.CRT 根证书,这样才能够拿这个根证书去进行认证我们 K8S api server 发过来的证书判断是否为真正的证书。

  • ca.crt,根证书。用于 client 端验证 API server 发送的证书

  • namespace,表示这个 service-account-token 的作用域名空间。

json web token (JWT):是为了在网络应用环境间传递声明而执行的一种基于 JSON 的开发标准。该 token 被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT 的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其他业务逻辑所必须的声明信息,该 token 也可以直接被用于认证,也可以被加密

默认情况下,每个 namespace 都会有一个 ServiceAccount,如果 pod 在创建时没有指定 ServiceAccount,就会使用 pod 所属的 namespace 的 ServiceAccount。

并且这个文件默认挂载目录是: /run/secrets/kubernetes.ioserviceaccount

之前也给大家讲了我们的 secret,并且也给大家说过一个信息就是在每一个名称空间中都会有自己自定义的这么一个 secret 。我们可以通过下面这个命令来看一下:

# 查看运行在 kube-system 名称空间下的 pod
[13:28:02 root@master-1 .kube]#kubectl get pod -n kube-system 

# 通过 exec 进入到 kube-system 名称空间下的  kube-proxy-rwgb2 pod  中并且使用的是 sh 命令
[14:10:40 root@master-1 .kube]#kubectl exec kube-proxy-rwgb2 -n kube-system -it -- /bin/sh
# cd /run/secrets/kubernetes.io
# ls
serviceaccount
# cd serviceaccount
# ls
ca.crt  namespace  token

# ca.crt 根的证书,namespace 以及 token。

这个就是 SA 也是我们 pod 认证到 API server 的这么一个标准。

10.2.4 总结

以上就是我们 kubernetes 集群中的认证关系了,也就意味着最终总结出来的就是,对于整个 K8S 集群认证来说采用的是 https 的这么一种认证方式。并且是一个双向认证方式,不仅仅客户端需要认证,服务器端也需要认证。如果是我们系统中的一些组件想去访问我们的 kubernetes 中的 API server 就会分为两种:

  • 一:我们的本机组件,比如 Controller Manager、Scheduler 默认会访问一个非安全加密端口.

  • 二:远程访问的组件,需要进行 https 的双向认证。

以上是组件和 api server 之间的认证关系,如果是 pod 想访问的话就必须要借助到我们的 (service account SA)

认证方案分为两种如图:

访问方式如上图所示,分为两种。分别是 pod 和 K8S 组件对 API server 的访问。

  • k8s 组件访问方式:如果是我们的 kubelet 通过我们的安全加密,如果是 kubectl、kube-proxy 这种需要用到手动颁发证书,有证书以后就可以通过 kubeconfig 文件去访问 API server。

  • pod:需要去通过 service account(SA)访问到我们的service-account-token,然后在通过service-account-token去访问到最后的 API server

以上就是一个认证的完整流程。

点赞