X509数字证书认证机制及kubeconfig配置文件

  • kubernetes支持的HTTPS客户端证书认证、token认证。其中基于SSL/TLS协议的客户端证书认证以其安全性高且易于实现等特性,而成为主要的使用方式之一
  • X509数字证书常用的方式有”单向认证”和”双向认证”,SSL/TLS最常见的使用场景是将x509证书与服务端相关联,但客户端不使用证书。单向认证是客户端能够验证服务端的身份,但是服务端无法验证客户端的身份,至少不能通过SSL/TLS协议进行。之所以如此,是因为SSL/TLS安全性最初是为互联网应用开发,保护客户端是高优先级的需求,它可以让客户端确保服务器不会被冒名顶替。如下图所示:
    kubernetes-安全-X509数字证书认证及kubeconfig配置文件 - 图1
  • 此外,基于其他机制(如HTTP基本认证)验证客户端身份可能更容易些,而且这些机制没有生成和分发x509数字证书的高昂开销。不过,在安全性较高的场景中,使用组织私有的证书分发系统也一样能够使用数字证书进行客户端验证。如下图所示:
    kubernetes-安全-X509数字证书认证及kubeconfig配置文件 - 图2
  • 在双向认证(服务端与客户端互相认证)的场景中,双方各自配备一套证书,并拥有心任的签证机构的证书列表。使用私有签证机构颁发的数字证书时,除了证书管理和分发,通常还要依赖用户手动的将私有签证机构签发的证书添加到信任的签证机构列表中。X509数字证书认证是kubernetes默认使用的认证机制,采用双向认证模式

kubernetes中使用X509数字证书认证体系(SSL/TLS)

  • 构建安全基础通信环境的kubernetes集群时,需要用到PKI基础设施以完成独立HTTPS安全通信及X509数字证书认证的场景有多种。如下图所示。API Server是整个kubernetes集群的通信网关,controller-manager,scheduler、kubelet以及kube-proxy等API Server的客户端均需要经过API Server与etcd通信,完成资源状态信息获取及更新等。同样出于安全通信的目的,master的各组件(API Server、Controller-manager和scheduler)需要基于SSL/TLS向外提供服务,而且与集群内部组件间进行通信时(主要是各节点上的kubelet和kube-proxy)还需要进行双向身份认证:
    kubernetes-安全-X509数字证书认证及kubeconfig配置文件 - 图3
  • kubernetes集群中各资源的状态信息,包括secret对象的敏感信息都是以明文方式存储于etcd中。因此etcd集群内各节点间的通信以及各节点与其客户端之间的通信都应该以加密的方式进行,并且需要进行身份验证
  • kubernetes集群中存在三个需要独立完成X509数字证书认证和HTTPS通信的体系
    • etcd集群成员,服务端及其客户端
    • API Server及其客户端,kubelet API 及其客户端
    • kubernetes认证代理体系中的服务端和客户端
  • 这三个独立的体现各自需要一个独立证书颁发机构为体系内的服务器和客户端颁发证书,完成体系内的组件身份认证同时又彼此隔离
  • 需要使用X509数字证书认证的组件
    • etcd集群CA及相关的数字证书: kubernetes的API Server将集群的状态数据存储到etcd集群当中,包括含有敏感数据的secret资源对象。出于提升服务可用性、数据冗余及安全性等目的,生成环境通常应该配置有3、5或者7个节点的etcd集群,集群内的各节点间基于HTTPS协议进行通信,它们使用Peer类型的数字证书进行通信时的身份认证。而且各etcd节点提供server类型的数字证书与客户端建立安全连接,并验证其客户端client类型的数字证书,并且它的证书需要一个单独的CA进行管理。kube-apiserver是唯一一个可直接与集群存储通信的组件,它也是etcd服务的客户端。
    • kubernetes集群CA及相关的数字证书:我们知道,kubernetes集群的其他各组件均需要通过kube-apiserver访问集群资源,同样处于安全性目的,API Server也要借助HTTPS协议与其客户端通信,而X509双向数字证书认证仅是API Server支持的认证方式中的一种,客户端也可能会使用HTTP Basic或者Beaere Token认证方式接入到API Server。另外,kubelet也通过HTTPS端点暴露了一组API,这些API提供了多个不同级别的敏感数据接口,并支持来自客户端的请求在节点和容器上执行不同级别的操作。默认情况下,匿名请求将自动隶属于system:unauthenticated组,其用户名为system:anonymous。不过,kubelet可使用--anonymous-auth=false选项拒绝匿名访问,并且可以通过--client-ca-file选项指定CA方式验证客户端身份。kubelet可直接使用kubernetes-ca,同时应该为kube-apiserver使用--kubelet-client-certificate--kubelet-client-key选项指定认证到kubelet的客户端证书与私钥
    • 认证代理服务体系CA及相关的数字证书:API Server支持将认证功能交由外部的其他认证服务代为完成,这些服务通过特定的响应头部返回身份验证的结果状态,API Server扩展服务就是认证代理的最常见应用场景之一
  • 除了API Server提供的核心API,kubernetes还支持通过聚合层(aggregation layer)对其进行扩展。简单来说,聚合层允许管理员在集群中部署使用其他kubernetes风格的API,例如service catalog或用户自定义的API Server等。聚合层本身打包在kube-apiserver程序中,并作为进程的一部分允许,但仅在管理员通过指定的APIService对象注册扩展资源之后,它才会代理转发响应的请求。而APIService则会由运行在kubernetes集群上的Pod中的extention-apiserver实现
  • 不过,只有kube-apiserver在启动时使用了如下选项,才能启用其内置的聚合层:
    • --requestheader-client-ca-file=<path to aggregator CA cert>
    • --requestheader-allowed-names=front-proxy-client
    • --requestheader-extra-headers-prefix=X-Remote-Extra-
    • --requestheader-group-headers=X-Remote-Group
    • --requestheader-username-headers=X-Remote-User
    • --proxy-client-cert-file=<path to aggregator proxy cert>
    • --proxy-client-key-file=<path to aggregator proxy key>
  • proxy-client-cert-file和proxy-client-key-file包含kube-aggregator执行客户端证书身份验证的证书和秘钥对,它使用requestheader-client-ca-file中指定的CA文件对聚合器证书进行签名。requestheader-allowed-names包含允许充当伪装前端代理的身份/名称列表(客户端证书中使用的CN),而requestheader-username-headersrequestheader-group-heradersrequestheader-extraheraders-prefix携带一个HTTP头的列表,用于携带远程用户信息
  • 完整允许的kubernetes系统需要为etcd、API Server及前端代理生成多个证书。如下图所示:
    kubernetes-安全-X509数字证书认证及kubeconfig配置文件 - 图4
  • 另外,其他集群上允许的Pod应用同其他客户端的通信经由不可信的网络传输时也可能需要用到TLS/SSL协议,例如Nginx pod与其客户端的通信,客户端来自于互联网时,此处通常需要配置一个公信的服务端证书
  • 显然,普通用户使用这种认证方式的前提是,它们各自拥有自己的数字证书,证书中的CN和O属性分别提供了准确的用户标识和用户组。API Server可接受或拒绝这些证书,评估标准在于证书是否由API Server信任的客户端证书CA(由选项--client-ca-file指定,默认为kubernetes-ca)所签发,但API Server自身并不了解这些证书,因此也不了解各个用户,它仅指定负责为各个客户端颁发证书的CA。因此,相较于静态令牌文件认证来说,X509数字证书认证实现了用户管理与kubernetes集群的分离,且有着更好的安全性
  • X509数字证书认证因其可以不依赖第三方服务、有着更好的安全性以及与API Server分离等优势,成为kubernetes系统内部默认使用的认证方式。但是,X509数字证书用于普通用户认证的缺陷也是显而易见的,他主要表现在如下两个方面。
    • 证书的到期时间在颁发时设定,其生命周期往往很长(数月甚至数年),且事实上的身份验证功能也是在颁发时完成,若撤销用户的可用身份只能用证书吊销功能完成
    • 现实使用中,证书通常由一些通用的签发机构颁发,而API Server需要信任该CA;显然,获得该CA使用权限的用户就能够授予自己可认证到kubernetes的任意凭据或身份(只要CA被信任,那么该CA签发的证书就会被kubernetes集群所信任,那么只要货得该CA使用权限的用户就能为自己签发证书并且利用签发的证书就可以认证到kubernetes集群),因而集群管理员必须自行集中管理证书,但是这个任务往往不会轻松
  • 对于大型组织来说,kubernetes系统用户量大且变动频繁,静态令牌文件的认证方式需要重启API Server,而X509认证中的证书维护开销较高且无法灵魂变动凭据生效期限,因此这些认证方式都非理想选择。实践中,人们通常使用ID Token进行kubernetes的普通用户身份认证,API Server的OpenID Connect令牌认证插件即用于该场景
  • API Server与其客户端之间采用HTTPS协议通信科兼顾实现通信与认证功能,它们之间通信的证书可由同一个CA进行管理。其客户端大体可由分为如下三类
    • 控制平面的kube-schedule和kube-controller-manager
    • 工作节点组件kubelet和kube-proxy:初次接入集群时,kubelet可由自动生成私钥和证书签署请求,并由master为其自动进行证书签名和颁发,这就是所谓的tls bootstrping
    • kubelet及其他形式的客户端,如Pod对象等

TLS Bootstrapping认证机制

  • TLS Bootstraping机制有什么用途呢?新的工作节点接入kubernetes集群时需要事先配置好相关的证书和私钥等以进行安全通信,管理员可以手动管理这些证书,也可以选择由kubelet自行生成私钥和自签证书。集群达到一定规模后,第一种方式无疑会为管理员带来不小的负担,但对于保障集群安全运行却又并不可少。第二种方式降低了管理员的工作量,却也损失了PKI本身具有的诸多优势。综合以上两种方案,取长补短之后,kubernetes采用了一种新的方法:kubernetes采用了由kubelet自行生成私钥和证书签署请求,而后发送给集群上的证书签署进程(CA),由管理员审核后予以签署或直接由控制器进程自动统一签署。这种方式即为kubelet TLS Bootstrapping,它实现了前述第一种的功能,却基本不增加管理员工作量。
  • 然而,一旦开启了TLS Bootstarpping功能,任何kubelet进程都可以向API Server发起验证请求并加入到集群,包括那些来自于非计划或者非授权的主机,这必将增大管理验证操作时的审核工作量。此时,就需要配合使用某种认证机制对kubelet发出的认证请求加以认证,为此,API Server设计了可经由--enable-bootstrap-token-auth选项启用的Bootstrap Token(引导令牌)认证插件。该插件用于加强TLS Bootstrapping机制,仅那些通过Bootstrap Token认证的请求才可以使用TLS Bootstrapping发送证书签署请求给控制平面,并由相应的审批控制器(approval controller)完成证书签署和颁发
  • kubeadm启用了节点加入集群时的证书自动签署功能,因此加入过程在kubeadm join命令成功后既完成
  • kubelet会把签署后的证书及配对的私钥存储到--cert-dir选项指定的目录下,并以之生成kubeconfig格式的配置文件,该文件的保存路径以--kubeconfig选项指定,它保存有API Server的地址以及认证凭据。若指定的kubeconfig配置文件不存在,kubelet会转而使用Bootstrap Token,从API Server自动请求完成TLS Bootstrapping过程。
  • kube-controller-manager内部有一个用于证书颁发的控制循环,它采用类似于cfssl签证器格式的自动签证器,签证依赖于CA提供加密组件支撑,此CA还必须被kube-apiserver的--client-ca-file选项指定的CA信任以用于认证。颁发的所有证书都仅有一年有效期限。正常使用中的kubernetes集群需要在证书过期之前完成,以免集群服务不可用。较新版本的kubeadm部署工具已经能够自动完成更新,如下第一条命令用于检测证书有效期限,在接近过期的情况下,即可使用第二条命令进行更新
  1. [root@kube-master-01 ~]# kubeadm alpha certs check-expiration
  2. [check-expiration] Reading configuration from the cluster...
  3. [check-expiration] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -oyaml'
  4. CERTIFICATE EXPIRES RESIDUAL TIME CERTIFICATE AUTHORITY EXTERNALLY MANAGED
  5. admin.conf Aug 19, 2022 07:07 UTC 346d no
  6. apiserver Aug 19, 2022 07:07 UTC 346d ca no
  7. apiserver-etcd-client Aug 19, 2022 07:07 UTC 346d etcd-ca no
  8. apiserver-kubelet-client Aug 19, 2022 07:07 UTC 346d ca no
  9. controller-manager.conf Aug 19, 2022 07:07 UTC 346d no
  10. etcd-healthcheck-client Aug 19, 2022 07:06 UTC 346d etcd-ca no
  11. etcd-peer Aug 19, 2022 07:06 UTC 346d etcd-ca no
  12. etcd-server Aug 19, 2022 07:06 UTC 346d etcd-ca no
  13. front-proxy-client Aug 19, 2022 07:07 UTC 346d front-proxy-ca no
  14. scheduler.conf Aug 19, 2022 07:07 UTC 346d no
  15. CERTIFICATE AUTHORITY EXPIRES RESIDUAL TIME EXTERNALLY MANAGED
  16. ca Aug 02, 2031 09:39 UTC 9y no
  17. etcd-ca Aug 02, 2031 09:39 UTC 9y no
  18. front-proxy-ca Aug 02, 2031 09:39 UTC 9y no
  19. [root@kube-master-01 ~]#
  20. [root@kube-master-01 ~]# kubeadm alpha certs renew all
  21. [renew] Reading configuration from the cluster...
  22. [renew] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -oyaml'
  23. certificate embedded in the kubeconfig file for the admin to use and for kubeadm itself renewed
  24. certificate for serving the Kubernetes API renewed
  25. certificate the apiserver uses to access etcd renewed
  26. certificate for the API server to connect to kubelet renewed
  27. certificate embedded in the kubeconfig file for the controller manager to use renewed
  28. certificate for liveness probes to healthcheck etcd renewed
  29. certificate for etcd nodes to communicate with each other renewed
  30. certificate for serving etcd renewed
  31. certificate for the front proxy client renewed
  32. certificate embedded in the kubeconfig file for the scheduler manager to use renewed
  33. [root@kube-master-01 ~]#
  • kubernetes1.8之后的版本中使用的csrapproving审批控制器内置于kube-controller-manager,并且默认为启用状态。此审批控制器使用SubjectAccessview API 确认给定的用户是否有权限请求CSR(证书签署请求),而后根据授权结果判定是否予以签署。不过为了避免与其他审批器发生冲突,内建的审批器并不会显式拒绝CSR,而只是忽略他们。

kubeconfig配置文件

  • 基于无状态协议HTTP/HTTPS的API Server需要验证每次连接请求中的用户身份,因而kube-controller-manager、kube-scheduler和kube-proxy等各类客户端组件必须能自动完成身份证信息的提交,但通过程序选项来提供这些信息会导致敏感信息泄漏。另外,管理员还面临着使用kubectl工具分别接入不同集群时的认证及认证信息映射难题。为此,kubernetes设计了一种称为kubeconfig的配置文件,它保存有接入一到多个kubernetes集群的相关配置信息,并允许管理员按需在各配置间灵活切换,包括kubectl,kubelt和kube-controller-manager等在内的API Server的各类客户端都可以使用kubeconfig配置文件提供接入多个集群的相关配置信息,包括各API Server的URL及认证信息等。而且能够设置成不同的上下文环境,并在各环境之间快速切换。如下图所示
    kubernetes-安全-X509数字证书认证及kubeconfig配置文件 - 图5
  • 客户端程序可以通过默认路径--kubeconfig选项或者KUBECONFIG环境变量自定义需要加载的kubeconfig文件,从而能够在每次的访问请求中可认证到目标API Server

kubeconfig文件格式

  • kubeconfig文件中,各集群的接入端点以列表形式定义在cluster配置段中,每个列表项代表一个kubernetes集群,并拥有名称标识;各身份证认证信息(credentials)定义在users配置段中,每个列表项代表一个能够认证到某kubernetes集群的凭据。将身份凭据与集群分开定义以便复用,具体使用时还要以context(上下文)在二者之间按需建立映射关系,各context以列表形式定义在contexts配置段中,而当前映射的关系则定义在current-context配置段中。
    kubernetes-安全-X509数字证书认证及kubeconfig配置文件 - 图6
  • 使用kubeadm初始化kubernetes集群过程中,在master节点上生成的/etc/kubernetes/admin.conf文件就是一个kubeconfig格式的配置文件,它是由kubeadmin init命令自动生成,可以由kubectl加载后接入当前集群的API Server。kubectl加载kubeconfig文件的默认路径是$HOME/.kube/config,在kubeadmin init命令初始化集群过程中有一个步骤便是将/etc/kubernetes/admin.conf复制为默认搜索路径上的文件。当然,我们也可以通过—kubeconfig选项或KUBECONFIG环境变量将其改为其他路径
  • kubectl config view命令能打印出kubeconfig文件的内容,下面的命令结果显示了默认路径下的文件配置,包括集群列表,用户列表,上下文列表以及当前使用的上下文(current-context)等。
  1. [root@jenkins serviceaccount]# kubectl config view
  2. apiVersion: v1
  3. clusters:
  4. - cluster:
  5. certificate-authority-data: DATA+OMITTED
  6. server: https://172.18.14.244:6443
  7. name: kubernetes
  8. contexts:
  9. - context:
  10. cluster: kubernetes
  11. user: kubernetes-admin
  12. name: kubernetes-admin@kubernetes
  13. current-context: kubernetes-admin@kubernetes
  14. kind: Config
  15. preferences: {}
  16. users:
  17. - name: kubernetes-admin
  18. user:
  19. client-certificate-data: REDACTED
  20. client-key-data: REDACTED
  21. [root@jenkins serviceaccount]#
  • 事实上,任何类型的API Server客户端都可以使用kubeconfig进行配置,例如kubernetes Node之上的kubelet和kube-proxy也需要将其用到的认证信息保存于专用的kubeconfig文件中,并通过—kubeconfig选项进行加载。kubeconfig文件的定义中包含了了一下几项主要的配置
    • clusters: 集群列表,包含访问API Server的URL和所属集群的名称等
    • contexts:kubelet的可用上下文列表,由用户列表中的某特定用户名称和集群列表中的某特定集群组成组合而成
    • users: 用户列表,包含访问API Server时的用户名和认证信息
    • current-context: kubelet当前使用的上下文名称,既上下文列表中的某个特定项
  • 用户可以在kubeconfig配置文件中按需自定义相关的配置信息,以实现使用不同的用户账户接入集群等功能。kubeconfig是一个文本文件,尽管可以使用文本处理工具直接编辑它,但强烈建议用户使用kubectl config及其子命令进行该文件的设定,以便利用其自动进行预防检测等额功能。kubectl config的常用子命令有如下几项:
    • view:打印出kubeconfig文件内容
    • set-cluster:设置新的集群信息,以单独的列表保存于cluster配置段
    • set-credentials: 设置认证凭据,保存为users配置段的一个列表项
    • set-context:设置新的上下文信息,保存为contexts配置段的一个列表项
    • use-context:设置current-context配置段,确定当前以哪个用户的身份接入到集群之中
    • delete-cluster:删除cluster中指定的列表项
    • delete-context:删除contexts中指定的列表项
    • get-cluster:获取cluster中定义的集群列表
    • get-contexts:获取contexts中定义的上下文列表
  • kubectl config命令的相关操作将针对加载的单个kubeconfig文件进行,它根据其优先级由高到底,依次搜索—kubeconfig选项指定的文件,KUBECONFIG环境变量指定的默认文件和默认的$HOME/.kube/config文件,以其中任何一种方式加载到配置文件后即可终止搜索过程。不过,kubectl config命令支持同时使用多个kubeconfig文件,以及将多个配置文件合并为一个。

自定义kubeconfig配置文件

  • 通常,一个完整kubeconfig配置的定义至少应该包含集群,身份凭据,上下文及当前上下文四项,但是在保存有集群身份凭据的现有kubeconfig文件基础上添加新的上下文时,可能只需要提供身份凭据而复用已有的集群定义,具体的操作步骤要按实际进行判定
  • 之前有说过,使用kubeadm部署的kubernetes集群默认提供了拥有集群管理权限的kubeconfig配置文件,其默认路径在/etc/kubernetes/admin.conf,它可以被复制到任何有着kubectl的主机上用于管理整个集群,除此之外,管理员还可以创建其他基于SSL/TLS认证的自定义用户账号,以授予非管理员级别的集群资源使用权限。其配置过程由两部分组成:
    • 为用户创建专用私钥及证书我呢见
    • 将其配置于某个kubeconfig文件中
  • 例如,我们下面尝试创建一个新的kubeconfig文件,设定它使用此前定义的基于静态token认证的ilinux用户接入到现有的kubernetes集群,该集群API Server的网络端点为https://k8s-api.ilinux.io:6443,相关的CA证书保存在master节点上的/etc/kubernetes/pki/ca.crt文件中,而配置结果则使用—kubeconfig选项存在当前用户主目录下的.kube/kube-dev.config文件中

基于token的身份凭据

添加集群配置

  • 添加集群配置,包括集群名称、API Server URL和信任的CA证书;cluster配置段中的各列表项名称需要唯一
  1. [root@kube-master-01 ~]# kubectl config set-cluster kube-dev --embed-certs=true \
  2. > --certificate-authority=/etc/kubernetes/pki/ca.crt \
  3. > --server="https://172.18.14.244:6443" \
  4. > --kubeconfig=$HOME/.kube/kube-dev.config
  5. Cluster "kube-dev" set.
  6. [root@kube-master-01 ~]#

添加身份凭据

  • 添加身份凭据,使用token文件认证认证的客户端提供静态token
  1. [root@kube-master-01 ~]# TOKEN=$(awk -F "," '$2=="ilinux"{print $1}' /etc/kubernetes/authfiles/token.csv)
  2. [root@kube-master-01 ~]# kubectl config set-credentials ilinux \
  3. > --token="$TOKEN" \
  4. > --kubeconfig=$HOME/.kube/kube-dev.config
  5. User "ilinux" set.
  6. [root@kube-master-01 ~]#

建设集群的映射关系

  • 以用户ilinux的身份凭据与kube-dev集群建立映射关系
  1. [root@kube-master-01 ~]# kubectl config set-context ilinux@kube-dev \
  2. > --cluster=kube-dev --user=ilinux \
  3. > --kubeconfig=$HOME/.kube/kube-dev.config
  4. Context "ilinux@kube-dev" created.
  5. [root@kube-master-01 ~]#

设置上下文

  1. [root@kube-master-01 ~]# kubectl config use-context ilinux@kube-dev \
  2. > --kubeconfig=$HOME/.kube/kube-dev.config
  3. Switched to context "ilinux@kube-dev".
  4. [root@kube-master-01 ~]#

查看kubeconfig配置文件

  • 查看kube-dev.config配置文件,确认其配置信息
  1. [root@kube-master-01 ~]# kubectl config view --kubeconfig=$HOME/.kube/kube-dev.config
  2. apiVersion: v1
  3. clusters:
  4. - cluster:
  5. certificate-authority-data: DATA+OMITTED
  6. server: https://k8s-api.ilinux.io:6443
  7. name: kube-dev
  8. contexts:
  9. - context:
  10. cluster: kube-dev
  11. user: ilinux
  12. name: ilinux@kube-dev
  13. current-context: ilinux@kube-dev
  14. kind: Config
  15. preferences: {}
  16. users:
  17. - name: ilinux
  18. user:
  19. token: REDACTED
  20. [root@kube-master-01 ~]#

测试

  • 使用该kubeconfig中的当前上下文进行测试访问;该用户被授权了default名称空间的所有访问权限,因而不具有列出集群级别资源的权限,但能查看default名称空间的状态
  1. [root@kube-master-01 ~]# kubectl get namespace --kubeconfig=$HOME/.kube/kube-dev.config
  2. Error from server (Forbidden): namespaces is forbidden: User "ilinux" cannot list resource "namespaces" in API group "" at the cluster scope
  3. [root@kube-master-01 ~]#
  4. [root@kube-master-01 ~]# kubectl get namespace/default --kubeconfig=$HOME/.kube/kube-dev.config
  5. NAME STATUS AGE
  6. default Active 34d
  7. [root@kube-master-01 ~]#
  • 上面的第六步确认了自定义配置中的ilinux有效可用,它被API Server借助以token认证插件完成认证并标识为ilinux用户,从而拥有该用户的的资源操作权限。同样,我们也可以使用上面的步骤将另外一个用户以同样的方式添加到一个kubeconfig配置文件中,只是无需再执行第一步即可
  • 事实上除了静态令牌认证,客户端认证到API Server的各种令牌都可以使用这种方式添加到kubeconfig文件中,包括ServiceAccount令牌,openID Connnect令牌和BootStrap令牌等。
  • 当kubectl引用了拥有两个及以上context的kubeconfig文件时,可以随时通过kubectl config use-context命令在不同上下文之间切换,它们可能使用不同的身份凭据接入相同的集群或不同的集群之上。如下面的命令结果标识当前加载的配置文件中一共有两个context,而拥有星号标识的是当前使用的context,既current-contxt
  1. [root@kube-master-01 ~]# kubectl config get-contexts --kubeconfig=$HOME/.kube/kube-dev.config
  2. CURRENT NAME CLUSTER AUTHINFO NAMESPACE
  3. * ik8s@kube-dev kube-dev ik8s
  4. ilinux@kube-dev kube-dev ilinux
  5. [root@kube-master-01 ~]#
  • 可以使用kubectl config use-context命令切换到另外一个context
  1. [root@kube-master-01 ~]# kubectl config use-context ilinux@kube-dev \
  2. > --kubeconfig=$HOME/.kube/kube-dev.config
  3. Switched to context "ilinux@kube-dev".
  4. [root@kube-master-01 ~]#
  5. [root@kube-master-01 ~]# kubectl config get-contexts --kubeconfig=$HOME/.kube/kube-dev.config
  6. CURRENT NAME CLUSTER AUTHINFO NAMESPACE
  7. ik8s@kube-dev kube-dev ik8s
  8. * ilinux@kube-dev kube-dev ilinux
  9. [root@kube-master-01 ~]#
  • 实践中,API Server支持的X509数字证书认证和OpenID Connect令牌认证才是客户端使用最多的认证方式

基于X509数字证书的认证方式

  • kubeadm部署的kubernetes集群的过程中会自动生成多个kubeconfig文件,它们是默认位于/etc/kubernetes目录下以.conf为后缀的文件,前缀名称代表了它的适用场景,其中的admin.conf中保存了以X509数字证书格式提供身份凭据的kubernetes-admin用户,该用户能够以管理员的身份对当前集群发起资源操作请求
  • 由kubeadm初始化的kubernetes集群上,kube-apiserver默认信任的CA就是集群自己的kubernetes-ca,该CA的数字证书是master节点之上的/etc/kubernetes/pki/ca.crt文件。于是,客户端按需生成证书签署请求,再由管理员通过kubernetes-ca为客户端签署证书,便可让客户端以其证书中的CN为用户名认证到API Server上。为了便于说明,下面有一个具体的示例可以看一下,将客户端生成私钥和证书签署请求,服务器签署该请求,以及客户端将证书配置为kubeconfig文件的步骤统一进行说明,所有操作都需要在master节点上运行

生成私钥文件

  • 以客户端的身份,生成目标用户账号kube-user的私钥及证书签署请求,保存在默认的/etc/kubernetes/pki目录中,也可以使用自定义目录,注意路径即可。
  • 生成私钥文件,其权限应该为600以阻止其他用户读取,可以直接在master节点用root用户操作即可,如果需要使用其他用户使用su - username切换到其他用户操作即可
  1. [root@kube-master-01 ~]# cd /etc/kubernetes/pki/
  2. [root@kube-master-01 pki]# (umask 077; openssl genrsa -out kube-user.key 2048)
  3. Generating RSA private key, 2048 bit long modulus
  4. .+++
  5. .........................................................+++
  6. e is 65537 (0x10001)
  7. [root@kube-master-01 pki]#
  8. [root@kube-master-01 pki]# ls
  9. ...
  10. ... kube-user.key
  11. [root@kube-master-01 pki]#

创建证书签署请求

  • 创建证书签署请求,-subj选项中的CN值将被API Server识别为用户名,并且在kubeconfig文件中作为用户名使用,O的值将被识别为用户组
  1. [root@kube-master-01 pki]# openssl req -new -key kube-user.key -out kube-user.csr -subj "/CN=kube-user/O=kubeusers"
  2. [root@kube-master-01 pki]#
  3. [root@kube-master-01 pki]# ls
  4. ... kube-user.key
  5. ... kube-user.csr
  6. [root@kube-master-01 pki]#

签署证书

  • 之前有说到过,使用kubeadm部署的kubernetes集群,kube-apiserver默认信任的CA就是集群自己的kubernetes-ca。使用kubernetes-ca的身份签署上面生成的证书签署请求,直接读取CSR相关的文件即可,并将签署后的证书仍然保存到/etc/kubernetes/pki目录
  • 基于kubernetes-ca签署证书,设置证书的有效时长,注意kubernetes-ca的证书路径,我这边使用的是默认的路径/etc/kubernetes/pki
  1. [root@kube-master-01 pki]# openssl x509 -req -days 365 -CA ca.crt \
  2. > -CAkey ca.key \
  3. > -CAcreateserial \
  4. > -in /etc/kubernetes/pki/kube-user.csr \
  5. > -out /etc/kubernetes/pki/kube-user.crt
  6. Signature ok
  7. subject=/CN=kube-user/O=kubeusers
  8. Getting CA Private Key
  9. [root@kube-master-01 pki]#
  10. [root@kube-master-01 pki]#
  11. [root@kube-master-01 pki]# ll kube-user.crt
  12. -rw-r--r-- 1 root root 1005 Sep 8 10:54 kube-user.crt
  13. [root@kube-master-01 pki]#
  • 必要时,还可以验证生成的数字证书的相关信息(可选)
  1. [root@kube-master-01 pki]# openssl x509 -in kube-user.crt -text -noout
  2. ...
  3. ...
  4. Signature Algorithm: sha256WithRSAEncryption
  5. Issuer: CN=kubernetes
  6. Validity
  7. Not Before: Sep 8 02:54:59 2021 GMT
  8. Not After : Sep 8 02:54:59 2022 GMT
  9. Subject: CN=kube-user, O=kubeusers
  10. Subject Public Key Info:
  11. Public Key Algorithm: rsaEncryption
  12. Public-Key: (2048 bit)
  13. Modulus:
  14. ...
  15. ...

创建身份凭据

  • 以默认的管理员kubernetes-admin@kubernetes为新建的kube-user设置kubeconfig配置文件。将配置文件保存于当前系统用户的$HOME/.kube/config文件中。当然也可以为kubectl使用—kubeconfig选项指定自定义的专用文件路径。另外,因为指向当前集群的配置项已经存在,既位于cluster配置段中的kubernetes。这里直接复用该集群定义。也可以配置一个新的集群,生成一个全新的kubeconfig配置文件,具体的可以参考基于token的身份凭据的配置步骤
  • 使用X509数字证书及私钥创建身份凭据,列表项名称同目标用户名
  1. [root@kube-master-01 pki]# kubectl config set-credentials kube-user --embed-certs=true \
  2. > --client-certificate=/etc/kubernetes/pki/kube-user.crt \
  3. > --client-key=/etc/kubernetes/pki/kube-user.key
  4. User "kube-user" set.
  5. [root@kube-master-01 pki]#

配置上下文

  • 配置context,以kube-user的身份凭据访问已经定义的kubernetes集群,该context的名称为kube-user@kubernetes
  • 如果为管理多个集群设置了多个环境,则可以使用use-context来进行切换
  1. [root@kube-master-01 pki]# kubectl config set-context kube-user@kubernetes \
  2. > --cluster=kubernetes \
  3. > --user=kube-user
  4. Context "kube-user@kubernetes" created.
  5. [root@kube-master-01 pki]#

查看当前用户

  • 查看当前kubernetes集群使用的默认的用户
  • 因为x509使用的是默认的kubeconfig配置文件,所以这里并没有显示出之前创建的ik8silinux用户,因为这两个用户使用的是kube-dev.config配置文件,而kubectl默认如果不指定kubeconfig配置文件的话,则默认使用的是由kubeadm创建集群时所使用的kubeconfig配置文件
  1. [root@kube-master-01 pki]# kubectl config get-contexts
  2. CURRENT NAME CLUSTER AUTHINFO NAMESPACE
  3. kube-user@kubernetes kubernetes kube-user
  4. * kubernetes-admin@kubernetes kubernetes kubernetes-admin
  5. [root@kube-master-01 pki]#

指定需要使用的上下文

  • 切换上下文用于使用不同的用户访问集群资源
  • 将当前上下文切换为kube-user@kubernetes,或直接在kubectl命令上使用--context='kube-user@kubernetes',以完成该用户的认证测试。第一种方式之前演示过,这里使用第二种方式
  • 下面的命令结果可以看出提示没有权限,但事实上kube-user这个用户已经被API Server正确识别
  1. [root@kube-master-01 pki]# kubectl get namespace/default --context='kube-user@kubernetes'
  2. Error from server (Forbidden): namespaces "default" is forbidden: User "kube-user" cannot get resource "namespaces" in API group "" in the namespace "default"
  3. [root@kube-master-01 pki]#
  • 以上这些是我们使用自定义证书,实现了将kube-user用户认证到API Server,并将该用户的身份凭据保存到了kubeconfig文件中

多kubeconfig文件与合并

  • 至此,我们可以看到kubectl config一次仅能使用单个kubeconfig文件。事实上,若将两个文件路径以冒号分隔并赋值给KUBECONFIG环境变量,也能够让kubectl config一次加载多个文件信息,优先级由高到低为各文件自左而右的次序。
  • 下面两条命令的结果显示,左侧文件拥有较高的优先级,因而其配置的current-context成为默认使用的context
  1. [root@kube-master-01 pki]# export KUBECONFIG="$HOME/.kube/config:$HOME/.kube/kube-dev.config"
  2. [root@kube-master-01 pki]# kubectl config get-contexts
  3. CURRENT NAME CLUSTER AUTHINFO NAMESPACE
  4. ik8s@kube-dev kube-dev ik8s
  5. ilinux@kube-dev kube-dev ilinux
  6. kube-user@kubernetes kubernetes kube-user
  7. * kubernetes-admin@kubernetes kubernetes kubernetes-admin
  8. [root@kube-master-01 pki]#
  • 联合使用多个kubeconfig时,同样可以按需调整当前使用的context,其实现方式同使用单个kubeconfig文件并没有不同之处
  1. [root@kube-master-01 pki]# kubectl config use-context ik8s@kube-dev
  2. Switched to context "ik8s@kube-dev".
  3. [root@kube-master-01 pki]# kubectl config get-contexts
  4. CURRENT NAME CLUSTER AUTHINFO NAMESPACE
  5. * ik8s@kube-dev kube-dev ik8s
  6. ilinux@kube-dev kube-dev ilinux
  7. kube-user@kubernetes kubernetes kube-user
  8. kubernetes-admin@kubernetes kubernetes kubernetes-admin
  9. [root@kube-master-01 pki]#
  10. [root@kube-master-01 pki]# kubectl config use-context kubernetes-admin@kubernetes
  11. Switched to context "kubernetes-admin@kubernetes".
  12. [root@kube-master-01 pki]# kubectl config get-contexts
  13. CURRENT NAME CLUSTER AUTHINFO NAMESPACE
  14. ik8s@kube-dev kube-dev ik8s
  15. ilinux@kube-dev kube-dev ilinux
  16. kube-user@kubernetes kubernetes kube-user
  17. * kubernetes-admin@kubernetes kubernetes kubernetes-admin
  18. [root@kube-master-01 pki]#
  • kubectl config view命令会将多个配置文件的内容按给定的次序连接并输出,其风格类似于Linux系统的cat命令。但我们也能够在view命令中将加载的多个配置文件展平为单个配置文件的格式予以输出,并将结果保存在指定路径下便能狗将多个kubeconfig文件合并为一
  • 例如,下面的命令便将KUBECONFIG环境变量中的两个kubeconfig文件合并成了单个文件K
  1. [root@kube-master-01 kubernetes]# kubectl config view --merge --flatten > $HOME/.kube/kube.config
  2. [root@kube-master-01 kubernetes]
  • 此时,切换kubectl config加载新生成的kubeconfig配置文件,它便直接拥有了此前两个配置文件中定义的所有信息,且current-contxt以遵循此前命令中的设定
  1. [root@kube-master-01 pki]# KUBECONFIG=$HOME/.kube/kube.config
  2. [root@kube-master-01 pki]#
  3. [root@kube-master-01 pki]# kubectl config get-contexts
  4. CURRENT NAME CLUSTER AUTHINFO NAMESPACE
  5. ik8s@kube-dev kube-dev ilinux
  6. ilinux@kube-dev kube-dev ilinux
  7. kube-user@kubernetes kubernetes kube-user
  8. * kubernetes-admin@kubernetes kubernetes kubernetes-admin
  9. [root@kube-master-01 pki]#
  • 因为后面的文档当中会继续用到ilinux和ik8s等多个用户用来测试授权结果,因为这里直接$HOME/.kube/目录下合并生成的kube.config配置文件覆盖到默认的config文件中,以便能够随时切换到各用户
  1. [root@kube-master-01 pki]# cp $HOME/.kube/kube.config $HOME/.kube/config
  2. cp: overwrite ‘/root/.kube/config’? y
  3. [root@kube-master-01 pki]#
  • 为了方便后续的操作,最好还是把上下文切换到集群管理员kubernetes-admin@kubernetes
  1. [root@kube-master-01 ~]# kubectl config use-context kubernetes-admin@kubernetes
  2. Switched to context "kubernetes-admin@kubernetes".
  3. [root@kube-master-01 ~]#
  4. [root@kube-master-01 pki]# kubectl config current-context
  5. kubernetes-admin@kubernetes
  6. [root@kube-master-01 pki]#