Skip to content

13-访问K8s集群的安全策略 ​

你好,我是雪飞。

前面课程带你了解了 K8s 集群的大部分常用资源对象,现在你已经可以独立完整的部署各种应用、配置环境变量、网络访问以及存储资源。今天开始,我们进入到 K8s 高级篇的学习。我会带你了解 K8s 的安全相关策略和 Pod 的稳定性策略,掌握如何使用资源统计与日志来监控集群和排查故障,学习如何备份和恢复 etcd 数据以及升级 K8s 集群。

K8s 集群中承载着企业的关键应用和各种数据,它的安全性至关重要。在 CKA 考试中,常考两个安全策略,一个是访问 K8s 集群的安全策略,另一个是 Pod 相互访问的安全策略。这节课,我们先了解一下访问 K8s 集群的安全策略。

访问 K8s 集群的过程 ​

K8s 集群是通过 API Server 组件提供外部访问接口,我们使用 kubectl 命令操作集群时,实际上是向 K8s 集群发起一个 HTTPS 请求。请求中包含了发起方、操作行为和资源对象。例如,执行一条简单的 “kubectl get pod” 命令,其中 get 是操作行为,Pod 是要操作的资源对象,而操作发起方就是集群管理员。

既然所有对集群的访问都要通过 API Server,那么我们只需要对访问 API Server 的请求进行控制就可以保证访问集群的安全性。因此,当请求到达 API Server 时,K8s 设计了一个安全请求流程,经历 3 个过程:身份认证、鉴权和准入控制,然后才能操作各种资源对象。

图片

访问集群操作资源对象的过程,类似于进入公司财务部门修改账本数据。首先,进入公司大楼时需要经过“身份认证”,就像 K8s 中的身份认证组件一样,“身份认证”保安会查看你的员工卡来确认你是否有权限进入大楼。之后,当你找到财务室并准备进入时,会遇到“鉴权”保安,他会检查你的授权权限,从而确定你是否有权进入财务部修改账本。最后,即使你通过了前两项检查,还会有一个“准入控制”保安在你修改账本之前进行最终审查,确保你的操作不会违反规定,防止作假。只有通过全部 3 次检查,你才能修改账本。下面,我们就分别介绍一下怎么通过这3个检查。

身份认证 ​

K8s 中有两种身份:一种是人类用户,另一种是服务账号。

人类用户就是通过个人账号访问和操作集群的真实用户,例如集群管理员、运维人员、研发人员等等。服务账号(ServiceAccount,简称 SA)是一个代表应用程序 Pod 的账号,用于让集群内的 Pod 安全访问 K8s 的 API Server。例如当 Pod 中的应用需要使用 K8s 的 API Server 提供的接口时,它就会使用服务账号的身份认证信息来建立安全的连接。

对于人类用户的身份认证,主要是通过证书认证。而对于服务账号,主要是通过 Token 认证。

证书认证 ​

证书认证是基于 SSL/TLS 证书,类似 HTTPS 请求证书,请求发起方和 K8s 集群通过证书来相互验证身份,确保只有拥有有效证书的访问才能与 K8s 的 API Server 进行安全通信。

人类用户在使用 kubectl 命令访问和操作集群资源对象时,会使用一个 kubeconfig 配置文件,这个配置文件中包含了集群信息、证书信息以及上下文信息。你可能在想,自己在 Master 节点上使用 kubectl 命令的时候也没有用到 kubeconfig 配置文件呀,为啥就能直接访问集群?

其实在搭建集群的时候,我们在管理节点上执行过 3 条命令,就是把初始化集群时默认生成的管理员配置文件(/etc/kubernetes/admin.conf)复制到了 .kube 隐藏目录下保存为 config 文件,这样在你执行 kubectl 命令时默认会使用这个管理员的 kubeconfig 文件,所以我们就不用再加上任何参数来指定配置文件了。你可以去 .kube 目录下看一下这个文件。

yaml
[root@k8s-master ~]# cd .kube/
[root@k8s-master .kube]# cat config
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0...
    server: https://192.168.1.11 :6443
  name: kubernetes
contexts:
- context:
    cluster: kubernetes
    user: kubernetes-admin
  name: kubernetes-admin@kubernetes
current-context: kubernetes-admin@kubernetes
kind: Config
preferences: {}
users:
- name: kubernetes-admin
  user:
    client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0...
    client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQp...

从 config 文件中看出,它包含三部分:clusters 属性中是集群的相关信息;contexts 属性中是上下文信息;users 属性中是个人证书相关信息。

除了 K8s 的管理员配置文件,你也可以为其他同事创建 kubeconfig 配置文件,之后这些同事就可以使用自己的 kubeconfig 配置文件来访问集群了。但是有了 kubeconfig 配置文件,只是可以通过身份认证检查,并不代表这个用户就有操作集群的权限,我们还需要给他分配权限。

Token 认证 ​

对于 K8s 另一种身份,服务账号没有 kubeconfig 配置文件,所以需要使用 Token 作为访问 API Server的身份认证。

在业务 Pod 使用服务账号时会生成身份认证的 Token 令牌,Pod 中的应用可以通过读取挂载目录下的文件获取 Token 令牌,并使用它来与 API Server 进行身份认证。

当创建一个新的命名空间时,K8s 会自动在这个命名空间下创建一个默认的服务账号(通常名为default)。当然我们也可以手动创建一个服务账号,使用 “kubectl create sa” 命令创建一个名称为 my-sa 的服务账号。

bash
[root@k8s-master ~]# kubectl create sa my-sa -n default
serviceaccount/my-sa created
[root@k8s-master ~]# kubectl get sa
NAME                     SECRETS   AGE
default                  0         12d
my-sa                    0         4s

在 Pod 的 YAML 文件中,通过在 spec 属性里增加 serviceAccountName 属性,可以指定 Pod 要使用的服务账号,如果不指定,则会使用该命名空间下的默认服务账号(default)。

当 Pod 部署启动时,K8s 会自动将服务账号的 Token 令牌挂载到容器的文件系统中,挂载目录通常是 “/var/run/secrets/kubernetes.io/serviceaccount”。Pod 容器中的应用就可以通过读取这些文件来获取令牌,从而与 API Server 进行安全通信。

在 Pod 中指定服务账号之前,我们也可以使用 kubectl 命令来测试服务账号的权限。通过增加 “–as=system:serviceaccount:default:my-sa” 参数来模拟使用服务账号 “my-sa” 的身份来执行 kubectl 命令,其中 system:serviceaccount 表示系统服务账号身份;default 表示 my-sa 的命名空间。

bash
[root@k8s-master ~]# kubectl get pod -n default --as=system:serviceaccount:default:my-sa
Error from server (Forbidden): pods is forbidden: User "system:serviceaccount:default:my-sa" cannot list resource "pods" in API group "" in the namespace "default"

返回结果可以看到虽然创建了 my-sa,但是没有分配任何权限,因此访问 Pod 是 Forbidden 禁止的。所以,下面我们就来了解如何给用户和服务账号分配适当的角色和权限。

鉴权 ​

K8s 支持多种鉴权方式,其中最常用的是 RBAC。RBAC 意思是基于角色的访问控制(Role-Based Access Control),通过 RBAC 机制,你可以创建角色来定义哪些用户和服务账号可以执行哪些操作,例如查看、创建、修改或删除特定的资源对象,这个过程叫做授权,授权之后的用户和服务账号就有了角色所定义的权限,在 K8s 的鉴权过程中,就会根据权限来放行操作。

使用 RBAC 授权需要了解几个概念。

  • Subject:主体,即赋予权限的对象。可以是用户(User)、用户组(Group)或服务账号(ServiceAccount)。
  • Role:角色。用于定义可以对 K8s 哪些资源对象操作的一组权限规则(Rule),其中包括资源对象所属的 API Groups、可操作的资源对象列表(Resources),以及资源对象的操作方式列表(verbs)。
  • RoleBinding:将定义好的角色和要授权的主体对象进行绑定。
  • ClusterRole 和 ClusterRoleBinding:Role 和 RoleBinding 只是授权特定命名空间的访问权限。而 ClusterRole 和 ClusterRoleBinding 是针对集群所有命名空间的授权,不受命名空间 NameSpace 的限制。

所以在使用 RBAC 时,首先确定授权主体,然后创建一个适合该主体对象的角色,角色里包含对资源对象操作的权限规则,最后将该角色与主体对象绑定,从而完成授权流程。

图片

现在我带你动手配置一个角色和绑定关系,从而熟悉一下授权流程。对用户授权和对服务账号授权流程是一样的,只是最后绑定的主体不同,所以我这里就使用刚才已经定义好的 my-sa 服务账号作为主体对象,给它授权读取默认命名空间(default)下的 Pod 以及管理 Deployment 的权限。

使用 Role 和 RoleBinding ​

角色和绑定关系有两种,一种是针对特定命名空间的 Role 和 RoleBinding,另一种是针对全部命名空间的 ClusterRole 和 ClusterRoleBinding。我们先来配置针对默认命名空间下的资源对象的操作权限控制。

1. 创建角色

通过 YAML 文件(deployment-pod-manager-role.yaml)来定义默认命名空间下的角色 Role。我们定义了一个 “deployment-pod-manager” 角色,包含两个权限规则:一个允许查看和列出 Pod,另一个允许查看、创建、更新和删除 Deployment 资源对象。

yaml
# dep-pod-manager-role.yaml 
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: deployment-pod-manager
  namespace: default    # 角色的权限限制在默认命名空间下
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "list"]
- apiGroups: ["apps"]
  resources: ["deployments"]
  verbs: ["get", "list", "create", "update", "delete"]

在规则 rules 属性里,可以配置多条规则,每条规则由以下属性组成:

  • apiGroups:表示资源对象所属的 API 组。通过 “kubectl api-resources” 命令可以查看资源对象的 API VERSION ,去掉 “/” 之后的版本号就是资源对象所属的 API Group。如果多个资源对象所属多个 apiGroups,可以在 [] 里写多个,例如:[“”, “apps”]。
  • resources:表示要操作的资源对象。可以在 [] 里写多个,例如:[“pods”, “deployments”],注意资源对象要使用复数形式。
  • verbs:表示对资源的操作列表。这些操作可以应用于上面资源对象列表中的所有资源对象,可以在 [] 里写多个,例如:[‘get’, ‘list’, ‘create’, ‘update’, ‘edit’, ‘delete’]。

部署角色,然后可以使用 “kubectl describe” 命令检查角色的规则是否正确。

bash
[root@k8s-master ~]# kubectl apply -f dep-pod-manager-role.yaml 
role.rbac.authorization.k8s.io/deployment-pod-manager created
[root@k8s-master ~]# kubectl describe role deployment-pod-manager
Name:         deployment-pod-manager
Labels:       <none>
Annotations:  <none>
PolicyRule:
  Resources         Non-Resource URLs  Resource Names  Verbs
  ---------         -----------------  --------------  -----
  deployments.apps  []                 []              [get list create update delete]
  pods              []                 []              [get list]

2. 绑定主体和角色

角色创建完成后,就可以使用 RoleBinding 绑定主体对象和角色了,我们创建一个 RoleBinding 的 YAML 文件(sa-role-binding.yaml),把 deployment-pod-manager 角色和主体 my-sa 这个服务账号绑定。

yaml
# sa-role-binding.yaml 
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: sa-deployment-pod-manager-rolebinding
  namespace: default
subjects:
- kind: ServiceAccount
  name: my-sa
  namespace: default   # my-sa的命名空间
roleRef:
  kind: Role
  name: deployment-pod-manager
  apiGroup: rbac.authorization.k8s.io
  • subjects:表示要绑定的主体对象,可以将多个对象同时绑定到一个角色中。如果主体是人类用户,只需要把 subjects 属性下的 kind 属性改为 User,name 属性改为用户证书中的名称,然后去掉 namespace 属性,改为 apiGroup: rbac.authorization.k8s.io,就可以绑定用户主体了。
  • roleRef:表示要绑定的角色。

部署角色的绑定关系,然后可以使用 “kubectl describe” 命令检查绑定关系。

bash
[root@k8s-master ~]# kubectl apply -f sa-role-binding.yaml 
rolebinding.rbac.authorization.k8s.io/sa-deployment-pod-manager-rolebinding created
[root@k8s-master ~]# kubectl describe rolebinding sa-deployment-pod-manager-rolebinding
Name:         sa-deployment-pod-manager-rolebinding
Labels:       <none>
Annotations:  <none>
Role:
  Kind:  Role
  Name:  deployment-pod-manager
Subjects:
  Kind            Name   Namespace
  ----            ----   ---------
  ServiceAccount  my-sa  default

3. 验证权限

最后,我们就可以使用 “–as” 参数模拟 my-sa 来操作 Pod 和 Deployment。

bash
[root@k8s-master ~]# kubectl create deployment sa-create-dep --image=nginx --replicas=3 --as=system:serviceaccount:default:my-sa
deployment.apps/sa-create-dep created

[root@k8s-master ~]# kubectl get pod --as=system:serviceaccount:default:my-sa
NAME                                READY   STATUS     RESTARTS   AGE
sa-create-dep-8df44697f-5nb94       1/1     Running    0          108m
sa-create-dep-8df44697f-9xwwt       1/1     Running    0          108m
sa-create-dep-8df44697f-fh8xs       1/1     Running    0          108m

[root@k8s-master ~]# kubectl get pod -n kube-system --as=system:serviceaccount:default:my-sa
Error from server (Forbidden): pods is forbidden: User "system:serviceaccount:default:my-sa" cannot list resource "pods" in API group "" in the namespace "kube-system"

根据返回结果看到,我们模拟 my-sa 服务账号可以在默认命名空间下创建 Deployment,同时可以查看默认命名空间下的 Pod。这说明我们对 my-sa 的授权流程成功了,所以在 my-sa 访问集群操作资源对象的时候,K8s 的鉴权机制根据该账号的绑定的角色权限来决定是否放行操作。

但是,当我们想查看命名空间为 “kube-system” 下的 Pod 时,就没有权限了。因为使用 Role 和 RoleBinding 时,授权仅限于特定命名空间。若要授权查看所有的命名空间,需要使用 ClusterRole 和 ClusterRoleBinding。

使用 ClusterRole 和 ClusterRoleBinding ​

ClusterRole 和 ClusterRoleBinding 的用法和 Role、RoleBinding 非常类似,只需要分别在角色和角色绑定的 YAML 文件中修改 kind 的类型为 ClusterRole 和 ClusterRoleBinding,然后去掉 metadata 属性中的 “namespace: default”。这样角色和绑定关系就是对应所有的命名空间了,你可以自己尝试一下。

通过 kubectl 命令创建角色和绑定关系 ​

上面是使用 YAML 文件方式来创建角色和绑定关系,也可以使用 kubectl 命令,熟悉这种方式在 CKA 考试中更利于快速解答问题。

bash
# 创建集群角色 
kubectl create clusterrole <角色名称> --verb=<操作列表(逗号分隔)> --resource=<资源对象列表(逗号分隔)>

# 将服务账号绑定角色 
kubectl create clusterrolebinding <绑定关系名称> --serviceaccount=<命名空间>:<sa 名称> --clusterrole=<角色名称>

# 将用户绑定角色 
kubectl create rolebinding <绑定关系名称> --user=<用户名称> --role=<角色名称>

命令中的 clusterrole 和 clusterrolebinding 可以换成 role 和 rolebinding。

准入控制 ​

鉴权成功后,访问 API Server 的最后一关就到了准入控制。准入控制是一种安全机制,在资源对象被创建或修改之前,提供验证和修改这些操作的方法,目的是确保所有对集群资源对象的更改都符合预定的策略和标准。

准入控制是通过准入控制器(Admission Controllers)插件来实现的,每个准入控制器都可以实施不同的策略,例如验证请求的合法性、限制资源配额、执行安全检查或自动修复配置问题。K8s 提供了一些默认的准入控制器,我们不需要做任何修改。

小结 ​

今天,我给你介绍了访问 K8s 的 API Server 的过程。要想通过 API Server 提供的接口访问和操作集群资源对象,需要经过身份认证、鉴权和准入控制三个阶段。

第一个过程是身份认证,K8s 支持证书认证和 Token 令牌认证两种方式,对于人类用户的身份认证,主要是通过证书认证。而对于服务账号,主要是通过 Token 认证。在业务 Pod 使用服务账号时会生成身份认证的 Token 令牌,应用可以通过该令牌来与 API Server 进行身份认证。

第二个过程是基于 RBAC 的鉴权,通过 RBAC 机制来给不同用户或服务账号分配权限,通过定义角色(Role/ClusterRole)和角色绑定关系(RoleBinding/ClusterRoleBinding)来控制用户和服务账号的访问权限,确保遵循最小权限原则。我也带你动手完成一个实验,给服务账号配置了访问 Pod 和管理 Deployment 的权限,并且通过 “–as” 参数来模拟访问集群。

最后一个过程是准入控制,API Server 启动时加载准入控制器插件,在资源对象创建或修改前提供验证和修改的方法,确保符合集群安全策略。

思考题 ​

这就是今天的全部内容,在 CKA 中也会考到相关的知识点。我给你留一道练习题。

创建一个服务账号 my-sa,分配只能创建 deployment、daemonset 的权限,并通过 “–as” 参数测试你的配置结果。

相信经过动手实践,会让你对知识的理解更加深刻。

最近更新